Linux Audio

Check our new training course

Embedded Linux training

Mar 10-20, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright 2021, NXP Semiconductors
  3 */
  4#include <linux/pcs/pcs-xpcs.h>
  5#include <linux/of_mdio.h>
  6#include "sja1105.h"
  7
  8#define SJA1110_PCS_BANK_REG		SJA1110_SPI_ADDR(0x3fc)
  9
 10int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
 11{
 12	struct sja1105_mdio_private *mdio_priv = bus->priv;
 13	struct sja1105_private *priv = mdio_priv->priv;
 14	u64 addr;
 15	u32 tmp;
 16	u16 mmd;
 17	int rc;
 18
 19	if (!(reg & MII_ADDR_C45))
 20		return -EINVAL;
 21
 22	mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
 23	addr = (mmd << 16) | (reg & GENMASK(15, 0));
 24
 25	if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
 26		return 0xffff;
 27
 28	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)
 29		return NXP_SJA1105_XPCS_ID >> 16;
 30	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)
 31		return NXP_SJA1105_XPCS_ID & GENMASK(15, 0);
 32
 33	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
 34	if (rc < 0)
 35		return rc;
 36
 37	return tmp & 0xffff;
 38}
 39
 40int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
 41{
 42	struct sja1105_mdio_private *mdio_priv = bus->priv;
 43	struct sja1105_private *priv = mdio_priv->priv;
 44	u64 addr;
 45	u32 tmp;
 46	u16 mmd;
 47
 48	if (!(reg & MII_ADDR_C45))
 49		return -EINVAL;
 50
 51	mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
 52	addr = (mmd << 16) | (reg & GENMASK(15, 0));
 53	tmp = val;
 54
 55	if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
 56		return -EINVAL;
 57
 58	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
 59}
 60
 61int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
 62{
 63	struct sja1105_mdio_private *mdio_priv = bus->priv;
 64	struct sja1105_private *priv = mdio_priv->priv;
 65	const struct sja1105_regs *regs = priv->info->regs;
 66	int offset, bank;
 67	u64 addr;
 68	u32 tmp;
 69	u16 mmd;
 70	int rc;
 71
 72	if (!(reg & MII_ADDR_C45))
 73		return -EINVAL;
 74
 75	if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
 76		return -ENODEV;
 77
 78	mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
 79	addr = (mmd << 16) | (reg & GENMASK(15, 0));
 80
 81	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)
 82		return NXP_SJA1110_XPCS_ID >> 16;
 83	if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)
 84		return NXP_SJA1110_XPCS_ID & GENMASK(15, 0);
 85
 86	bank = addr >> 8;
 87	offset = addr & GENMASK(7, 0);
 88
 89	/* This addressing scheme reserves register 0xff for the bank address
 90	 * register, so that can never be addressed.
 91	 */
 92	if (WARN_ON(offset == 0xff))
 93		return -ENODEV;
 94
 95	tmp = bank;
 96
 97	rc = sja1105_xfer_u32(priv, SPI_WRITE,
 98			      regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
 99			      &tmp, NULL);
100	if (rc < 0)
101		return rc;
102
103	rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset,
104			      &tmp, NULL);
105	if (rc < 0)
106		return rc;
107
108	return tmp & 0xffff;
109}
110
111int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
112{
113	struct sja1105_mdio_private *mdio_priv = bus->priv;
114	struct sja1105_private *priv = mdio_priv->priv;
115	const struct sja1105_regs *regs = priv->info->regs;
116	int offset, bank;
117	u64 addr;
118	u32 tmp;
119	u16 mmd;
120	int rc;
121
122	if (!(reg & MII_ADDR_C45))
123		return -EINVAL;
124
125	if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
126		return -ENODEV;
127
128	mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
129	addr = (mmd << 16) | (reg & GENMASK(15, 0));
130
131	bank = addr >> 8;
132	offset = addr & GENMASK(7, 0);
133
134	/* This addressing scheme reserves register 0xff for the bank address
135	 * register, so that can never be addressed.
136	 */
137	if (WARN_ON(offset == 0xff))
138		return -ENODEV;
139
140	tmp = bank;
141
142	rc = sja1105_xfer_u32(priv, SPI_WRITE,
143			      regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
144			      &tmp, NULL);
145	if (rc < 0)
146		return rc;
147
148	tmp = val;
149
150	return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
151				&tmp, NULL);
152}
153
154enum sja1105_mdio_opcode {
155	SJA1105_C45_ADDR = 0,
156	SJA1105_C22 = 1,
157	SJA1105_C45_DATA = 2,
158	SJA1105_C45_DATA_AUTOINC = 3,
159};
160
161static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,
162				       int phy, enum sja1105_mdio_opcode op,
163				       int xad)
164{
165	const struct sja1105_regs *regs = priv->info->regs;
166
167	return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);
168}
169
170static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg)
171{
172	struct sja1105_mdio_private *mdio_priv = bus->priv;
173	struct sja1105_private *priv = mdio_priv->priv;
174	u64 addr;
175	u32 tmp;
176	int rc;
177
178	if (reg & MII_ADDR_C45) {
179		u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
180
181		addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
182						   mmd);
183
184		tmp = reg & MII_REGADDR_C45_MASK;
185
186		rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
187		if (rc < 0)
188			return rc;
189
190		addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
191						   mmd);
192
193		rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
194		if (rc < 0)
195			return rc;
196
197		return tmp & 0xffff;
198	}
199
200	/* Clause 22 read */
201	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
202
203	rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
204	if (rc < 0)
205		return rc;
206
207	return tmp & 0xffff;
208}
209
210static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg,
211				      u16 val)
212{
213	struct sja1105_mdio_private *mdio_priv = bus->priv;
214	struct sja1105_private *priv = mdio_priv->priv;
215	u64 addr;
216	u32 tmp;
217	int rc;
218
219	if (reg & MII_ADDR_C45) {
220		u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
221
222		addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
223						   mmd);
224
225		tmp = reg & MII_REGADDR_C45_MASK;
226
227		rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
228		if (rc < 0)
229			return rc;
230
231		addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
232						   mmd);
233
234		tmp = val & 0xffff;
235
236		rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
237		if (rc < 0)
238			return rc;
239
240		return 0;
241	}
242
243	/* Clause 22 write */
244	addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
245
246	tmp = val & 0xffff;
247
248	return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
249}
250
251static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
252{
253	struct sja1105_mdio_private *mdio_priv = bus->priv;
254	struct sja1105_private *priv = mdio_priv->priv;
255	const struct sja1105_regs *regs = priv->info->regs;
256	u32 tmp;
257	int rc;
258
259	rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
260			      &tmp, NULL);
261	if (rc < 0)
262		return rc;
263
264	return tmp & 0xffff;
265}
266
267static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
268				      u16 val)
269{
270	struct sja1105_mdio_private *mdio_priv = bus->priv;
271	struct sja1105_private *priv = mdio_priv->priv;
272	const struct sja1105_regs *regs = priv->info->regs;
273	u32 tmp = val;
274
275	return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
276				&tmp, NULL);
277}
278
279static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
280					    struct device_node *mdio_node)
281{
282	struct sja1105_mdio_private *mdio_priv;
283	struct device_node *np;
284	struct mii_bus *bus;
285	int rc = 0;
286
287	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio");
288	if (!np)
289		return 0;
290
291	if (!of_device_is_available(np))
292		goto out_put_np;
293
294	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
295	if (!bus) {
296		rc = -ENOMEM;
297		goto out_put_np;
298	}
299
300	bus->name = "SJA1110 100base-TX MDIO bus";
301	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
302		 dev_name(priv->ds->dev));
303	bus->read = sja1105_base_tx_mdio_read;
304	bus->write = sja1105_base_tx_mdio_write;
305	bus->parent = priv->ds->dev;
306	mdio_priv = bus->priv;
307	mdio_priv->priv = priv;
308
309	rc = of_mdiobus_register(bus, np);
310	if (rc) {
311		mdiobus_free(bus);
312		goto out_put_np;
313	}
314
315	priv->mdio_base_tx = bus;
316
317out_put_np:
318	of_node_put(np);
319
320	return rc;
321}
322
323static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
324{
325	if (!priv->mdio_base_tx)
326		return;
327
328	mdiobus_unregister(priv->mdio_base_tx);
329	mdiobus_free(priv->mdio_base_tx);
330	priv->mdio_base_tx = NULL;
331}
332
333static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
334					    struct device_node *mdio_node)
335{
336	struct sja1105_mdio_private *mdio_priv;
337	struct device_node *np;
338	struct mii_bus *bus;
339	int rc = 0;
340
341	np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio");
342	if (!np)
343		return 0;
344
345	if (!of_device_is_available(np))
346		goto out_put_np;
347
348	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
349	if (!bus) {
350		rc = -ENOMEM;
351		goto out_put_np;
352	}
353
354	bus->name = "SJA1110 100base-T1 MDIO bus";
355	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
356		 dev_name(priv->ds->dev));
357	bus->read = sja1105_base_t1_mdio_read;
358	bus->write = sja1105_base_t1_mdio_write;
359	bus->parent = priv->ds->dev;
360	mdio_priv = bus->priv;
361	mdio_priv->priv = priv;
362
363	rc = of_mdiobus_register(bus, np);
364	if (rc) {
365		mdiobus_free(bus);
366		goto out_put_np;
367	}
368
369	priv->mdio_base_t1 = bus;
370
371out_put_np:
372	of_node_put(np);
373
374	return rc;
375}
376
377static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
378{
379	if (!priv->mdio_base_t1)
380		return;
381
382	mdiobus_unregister(priv->mdio_base_t1);
383	mdiobus_free(priv->mdio_base_t1);
384	priv->mdio_base_t1 = NULL;
385}
386
387static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)
388{
389	struct sja1105_mdio_private *mdio_priv;
390	struct dsa_switch *ds = priv->ds;
391	struct mii_bus *bus;
392	int rc = 0;
393	int port;
394
395	if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write)
396		return 0;
397
398	bus = mdiobus_alloc_size(sizeof(*mdio_priv));
399	if (!bus)
400		return -ENOMEM;
401
402	bus->name = "SJA1105 PCS MDIO bus";
403	snprintf(bus->id, MII_BUS_ID_SIZE, "%s-pcs",
404		 dev_name(ds->dev));
405	bus->read = priv->info->pcs_mdio_read;
406	bus->write = priv->info->pcs_mdio_write;
407	bus->parent = ds->dev;
408	/* There is no PHY on this MDIO bus => mask out all PHY addresses
409	 * from auto probing.
410	 */
411	bus->phy_mask = ~0;
412	mdio_priv = bus->priv;
413	mdio_priv->priv = priv;
414
415	rc = mdiobus_register(bus);
416	if (rc) {
417		mdiobus_free(bus);
418		return rc;
419	}
420
421	for (port = 0; port < ds->num_ports; port++) {
422		struct mdio_device *mdiodev;
423		struct dw_xpcs *xpcs;
424
425		if (dsa_is_unused_port(ds, port))
426			continue;
427
428		if (priv->phy_mode[port] != PHY_INTERFACE_MODE_SGMII &&
429		    priv->phy_mode[port] != PHY_INTERFACE_MODE_2500BASEX)
430			continue;
431
432		mdiodev = mdio_device_create(bus, port);
433		if (IS_ERR(mdiodev)) {
434			rc = PTR_ERR(mdiodev);
435			goto out_pcs_free;
436		}
437
438		xpcs = xpcs_create(mdiodev, priv->phy_mode[port]);
439		if (IS_ERR(xpcs)) {
440			rc = PTR_ERR(xpcs);
441			goto out_pcs_free;
442		}
443
444		priv->xpcs[port] = xpcs;
445	}
446
447	priv->mdio_pcs = bus;
448
449	return 0;
450
451out_pcs_free:
452	for (port = 0; port < ds->num_ports; port++) {
453		if (!priv->xpcs[port])
454			continue;
455
456		mdio_device_free(priv->xpcs[port]->mdiodev);
457		xpcs_destroy(priv->xpcs[port]);
458		priv->xpcs[port] = NULL;
459	}
460
461	mdiobus_unregister(bus);
462	mdiobus_free(bus);
463
464	return rc;
465}
466
467static void sja1105_mdiobus_pcs_unregister(struct sja1105_private *priv)
468{
469	struct dsa_switch *ds = priv->ds;
470	int port;
471
472	if (!priv->mdio_pcs)
473		return;
474
475	for (port = 0; port < ds->num_ports; port++) {
476		if (!priv->xpcs[port])
477			continue;
478
479		mdio_device_free(priv->xpcs[port]->mdiodev);
480		xpcs_destroy(priv->xpcs[port]);
481		priv->xpcs[port] = NULL;
482	}
483
484	mdiobus_unregister(priv->mdio_pcs);
485	mdiobus_free(priv->mdio_pcs);
486	priv->mdio_pcs = NULL;
487}
488
489int sja1105_mdiobus_register(struct dsa_switch *ds)
490{
491	struct sja1105_private *priv = ds->priv;
492	const struct sja1105_regs *regs = priv->info->regs;
493	struct device_node *switch_node = ds->dev->of_node;
494	struct device_node *mdio_node;
495	int rc;
496
497	rc = sja1105_mdiobus_pcs_register(priv);
498	if (rc)
499		return rc;
500
501	mdio_node = of_get_child_by_name(switch_node, "mdios");
502	if (!mdio_node)
503		return 0;
504
505	if (!of_device_is_available(mdio_node))
506		goto out_put_mdio_node;
507
508	if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
509		rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
510		if (rc)
511			goto err_put_mdio_node;
512	}
513
514	if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
515		rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
516		if (rc)
517			goto err_free_base_tx_mdiobus;
518	}
519
520out_put_mdio_node:
521	of_node_put(mdio_node);
522
523	return 0;
524
525err_free_base_tx_mdiobus:
526	sja1105_mdiobus_base_tx_unregister(priv);
527err_put_mdio_node:
528	of_node_put(mdio_node);
529	sja1105_mdiobus_pcs_unregister(priv);
530
531	return rc;
532}
533
534void sja1105_mdiobus_unregister(struct dsa_switch *ds)
535{
536	struct sja1105_private *priv = ds->priv;
537
538	sja1105_mdiobus_base_t1_unregister(priv);
539	sja1105_mdiobus_base_tx_unregister(priv);
540	sja1105_mdiobus_pcs_unregister(priv);
541}