1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/pcs/pcs-xpcs.h>
5 #include <linux/of_mdio.h>
8 #define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc)
10 int sja1105_pcs_mdio_read_c45(struct mii_bus
*bus
, int phy
, int mmd
, int reg
)
12 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
13 struct sja1105_private
*priv
= mdio_priv
->priv
;
18 addr
= (mmd
<< 16) | reg
;
20 if (mmd
!= MDIO_MMD_VEND1
&& mmd
!= MDIO_MMD_VEND2
)
23 if (mmd
== MDIO_MMD_VEND2
&& (reg
& GENMASK(15, 0)) == MII_PHYSID1
)
24 return NXP_SJA1105_XPCS_ID
>> 16;
25 if (mmd
== MDIO_MMD_VEND2
&& (reg
& GENMASK(15, 0)) == MII_PHYSID2
)
26 return NXP_SJA1105_XPCS_ID
& GENMASK(15, 0);
28 rc
= sja1105_xfer_u32(priv
, SPI_READ
, addr
, &tmp
, NULL
);
35 int sja1105_pcs_mdio_write_c45(struct mii_bus
*bus
, int phy
, int mmd
,
38 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
39 struct sja1105_private
*priv
= mdio_priv
->priv
;
43 addr
= (mmd
<< 16) | reg
;
46 if (mmd
!= MDIO_MMD_VEND1
&& mmd
!= MDIO_MMD_VEND2
)
49 return sja1105_xfer_u32(priv
, SPI_WRITE
, addr
, &tmp
, NULL
);
52 int sja1110_pcs_mdio_read_c45(struct mii_bus
*bus
, int phy
, int mmd
, int reg
)
54 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
55 struct sja1105_private
*priv
= mdio_priv
->priv
;
56 const struct sja1105_regs
*regs
= priv
->info
->regs
;
62 if (regs
->pcs_base
[phy
] == SJA1105_RSV_ADDR
)
65 addr
= (mmd
<< 16) | reg
;
67 if (mmd
== MDIO_MMD_VEND2
&& (reg
& GENMASK(15, 0)) == MII_PHYSID1
)
68 return NXP_SJA1110_XPCS_ID
>> 16;
69 if (mmd
== MDIO_MMD_VEND2
&& (reg
& GENMASK(15, 0)) == MII_PHYSID2
)
70 return NXP_SJA1110_XPCS_ID
& GENMASK(15, 0);
73 offset
= addr
& GENMASK(7, 0);
75 /* This addressing scheme reserves register 0xff for the bank address
76 * register, so that can never be addressed.
78 if (WARN_ON(offset
== 0xff))
83 rc
= sja1105_xfer_u32(priv
, SPI_WRITE
,
84 regs
->pcs_base
[phy
] + SJA1110_PCS_BANK_REG
,
89 rc
= sja1105_xfer_u32(priv
, SPI_READ
, regs
->pcs_base
[phy
] + offset
,
97 int sja1110_pcs_mdio_write_c45(struct mii_bus
*bus
, int phy
, int mmd
, int reg
,
100 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
101 struct sja1105_private
*priv
= mdio_priv
->priv
;
102 const struct sja1105_regs
*regs
= priv
->info
->regs
;
108 if (regs
->pcs_base
[phy
] == SJA1105_RSV_ADDR
)
111 addr
= (mmd
<< 16) | reg
;
114 offset
= addr
& GENMASK(7, 0);
116 /* This addressing scheme reserves register 0xff for the bank address
117 * register, so that can never be addressed.
119 if (WARN_ON(offset
== 0xff))
124 rc
= sja1105_xfer_u32(priv
, SPI_WRITE
,
125 regs
->pcs_base
[phy
] + SJA1110_PCS_BANK_REG
,
132 return sja1105_xfer_u32(priv
, SPI_WRITE
, regs
->pcs_base
[phy
] + offset
,
136 enum sja1105_mdio_opcode
{
137 SJA1105_C45_ADDR
= 0,
139 SJA1105_C45_DATA
= 2,
140 SJA1105_C45_DATA_AUTOINC
= 3,
143 static u64
sja1105_base_t1_encode_addr(struct sja1105_private
*priv
,
144 int phy
, enum sja1105_mdio_opcode op
,
147 const struct sja1105_regs
*regs
= priv
->info
->regs
;
149 return regs
->mdio_100base_t1
| (phy
<< 7) | (op
<< 5) | (xad
<< 0);
152 static int sja1105_base_t1_mdio_read_c22(struct mii_bus
*bus
, int phy
, int reg
)
154 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
155 struct sja1105_private
*priv
= mdio_priv
->priv
;
160 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C22
, reg
& 0x1f);
162 rc
= sja1105_xfer_u32(priv
, SPI_READ
, addr
, &tmp
, NULL
);
169 static int sja1105_base_t1_mdio_read_c45(struct mii_bus
*bus
, int phy
,
172 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
173 struct sja1105_private
*priv
= mdio_priv
->priv
;
178 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C45_ADDR
, mmd
);
180 rc
= sja1105_xfer_u32(priv
, SPI_WRITE
, addr
, ®
, NULL
);
184 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C45_DATA
, mmd
);
186 rc
= sja1105_xfer_u32(priv
, SPI_READ
, addr
, &tmp
, NULL
);
193 static int sja1105_base_t1_mdio_write_c22(struct mii_bus
*bus
, int phy
, int reg
,
196 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
197 struct sja1105_private
*priv
= mdio_priv
->priv
;
201 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C22
, reg
& 0x1f);
205 return sja1105_xfer_u32(priv
, SPI_WRITE
, addr
, &tmp
, NULL
);
208 static int sja1105_base_t1_mdio_write_c45(struct mii_bus
*bus
, int phy
,
209 int mmd
, int reg
, u16 val
)
211 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
212 struct sja1105_private
*priv
= mdio_priv
->priv
;
217 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C45_ADDR
, mmd
);
219 rc
= sja1105_xfer_u32(priv
, SPI_WRITE
, addr
, ®
, NULL
);
223 addr
= sja1105_base_t1_encode_addr(priv
, phy
, SJA1105_C45_DATA
, mmd
);
227 return sja1105_xfer_u32(priv
, SPI_WRITE
, addr
, &tmp
, NULL
);
230 static int sja1105_base_tx_mdio_read(struct mii_bus
*bus
, int phy
, int reg
)
232 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
233 struct sja1105_private
*priv
= mdio_priv
->priv
;
234 const struct sja1105_regs
*regs
= priv
->info
->regs
;
238 rc
= sja1105_xfer_u32(priv
, SPI_READ
, regs
->mdio_100base_tx
+ reg
,
246 static int sja1105_base_tx_mdio_write(struct mii_bus
*bus
, int phy
, int reg
,
249 struct sja1105_mdio_private
*mdio_priv
= bus
->priv
;
250 struct sja1105_private
*priv
= mdio_priv
->priv
;
251 const struct sja1105_regs
*regs
= priv
->info
->regs
;
254 return sja1105_xfer_u32(priv
, SPI_WRITE
, regs
->mdio_100base_tx
+ reg
,
258 static int sja1105_mdiobus_base_tx_register(struct sja1105_private
*priv
,
259 struct device_node
*mdio_node
)
261 struct sja1105_mdio_private
*mdio_priv
;
262 struct device_node
*np
;
266 np
= of_get_compatible_child(mdio_node
, "nxp,sja1110-base-tx-mdio");
270 if (!of_device_is_available(np
))
273 bus
= mdiobus_alloc_size(sizeof(*mdio_priv
));
279 bus
->name
= "SJA1110 100base-TX MDIO bus";
280 snprintf(bus
->id
, MII_BUS_ID_SIZE
, "%s-base-tx",
281 dev_name(priv
->ds
->dev
));
282 bus
->read
= sja1105_base_tx_mdio_read
;
283 bus
->write
= sja1105_base_tx_mdio_write
;
284 bus
->parent
= priv
->ds
->dev
;
285 mdio_priv
= bus
->priv
;
286 mdio_priv
->priv
= priv
;
288 rc
= of_mdiobus_register(bus
, np
);
294 priv
->mdio_base_tx
= bus
;
302 static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private
*priv
)
304 if (!priv
->mdio_base_tx
)
307 mdiobus_unregister(priv
->mdio_base_tx
);
308 mdiobus_free(priv
->mdio_base_tx
);
309 priv
->mdio_base_tx
= NULL
;
312 static int sja1105_mdiobus_base_t1_register(struct sja1105_private
*priv
,
313 struct device_node
*mdio_node
)
315 struct sja1105_mdio_private
*mdio_priv
;
316 struct device_node
*np
;
320 np
= of_get_compatible_child(mdio_node
, "nxp,sja1110-base-t1-mdio");
324 if (!of_device_is_available(np
))
327 bus
= mdiobus_alloc_size(sizeof(*mdio_priv
));
333 bus
->name
= "SJA1110 100base-T1 MDIO bus";
334 snprintf(bus
->id
, MII_BUS_ID_SIZE
, "%s-base-t1",
335 dev_name(priv
->ds
->dev
));
336 bus
->read
= sja1105_base_t1_mdio_read_c22
;
337 bus
->write
= sja1105_base_t1_mdio_write_c22
;
338 bus
->read_c45
= sja1105_base_t1_mdio_read_c45
;
339 bus
->write_c45
= sja1105_base_t1_mdio_write_c45
;
340 bus
->parent
= priv
->ds
->dev
;
341 mdio_priv
= bus
->priv
;
342 mdio_priv
->priv
= priv
;
344 rc
= of_mdiobus_register(bus
, np
);
350 priv
->mdio_base_t1
= bus
;
358 static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private
*priv
)
360 if (!priv
->mdio_base_t1
)
363 mdiobus_unregister(priv
->mdio_base_t1
);
364 mdiobus_free(priv
->mdio_base_t1
);
365 priv
->mdio_base_t1
= NULL
;
368 static int sja1105_mdiobus_pcs_register(struct sja1105_private
*priv
)
370 struct sja1105_mdio_private
*mdio_priv
;
371 struct dsa_switch
*ds
= priv
->ds
;
376 if (!priv
->info
->pcs_mdio_read_c45
|| !priv
->info
->pcs_mdio_write_c45
)
379 bus
= mdiobus_alloc_size(sizeof(*mdio_priv
));
383 bus
->name
= "SJA1105 PCS MDIO bus";
384 snprintf(bus
->id
, MII_BUS_ID_SIZE
, "%s-pcs",
386 bus
->read_c45
= priv
->info
->pcs_mdio_read_c45
;
387 bus
->write_c45
= priv
->info
->pcs_mdio_write_c45
;
388 bus
->parent
= ds
->dev
;
389 /* There is no PHY on this MDIO bus => mask out all PHY addresses
393 mdio_priv
= bus
->priv
;
394 mdio_priv
->priv
= priv
;
396 rc
= mdiobus_register(bus
);
402 for (port
= 0; port
< ds
->num_ports
; port
++) {
403 struct phylink_pcs
*pcs
;
405 if (dsa_is_unused_port(ds
, port
))
408 if (priv
->phy_mode
[port
] != PHY_INTERFACE_MODE_SGMII
&&
409 priv
->phy_mode
[port
] != PHY_INTERFACE_MODE_2500BASEX
)
412 pcs
= xpcs_create_pcs_mdiodev(bus
, port
);
418 priv
->pcs
[port
] = pcs
;
421 priv
->mdio_pcs
= bus
;
426 for (port
= 0; port
< ds
->num_ports
; port
++) {
427 if (priv
->pcs
[port
]) {
428 xpcs_destroy_pcs(priv
->pcs
[port
]);
429 priv
->pcs
[port
] = NULL
;
433 mdiobus_unregister(bus
);
439 static void sja1105_mdiobus_pcs_unregister(struct sja1105_private
*priv
)
441 struct dsa_switch
*ds
= priv
->ds
;
447 for (port
= 0; port
< ds
->num_ports
; port
++) {
448 if (priv
->pcs
[port
]) {
449 xpcs_destroy_pcs(priv
->pcs
[port
]);
450 priv
->pcs
[port
] = NULL
;
454 mdiobus_unregister(priv
->mdio_pcs
);
455 mdiobus_free(priv
->mdio_pcs
);
456 priv
->mdio_pcs
= NULL
;
459 int sja1105_mdiobus_register(struct dsa_switch
*ds
)
461 struct sja1105_private
*priv
= ds
->priv
;
462 const struct sja1105_regs
*regs
= priv
->info
->regs
;
463 struct device_node
*switch_node
= ds
->dev
->of_node
;
464 struct device_node
*mdio_node
;
467 rc
= sja1105_mdiobus_pcs_register(priv
);
471 mdio_node
= of_get_child_by_name(switch_node
, "mdios");
475 if (!of_device_is_available(mdio_node
))
476 goto out_put_mdio_node
;
478 if (regs
->mdio_100base_tx
!= SJA1105_RSV_ADDR
) {
479 rc
= sja1105_mdiobus_base_tx_register(priv
, mdio_node
);
481 goto err_put_mdio_node
;
484 if (regs
->mdio_100base_t1
!= SJA1105_RSV_ADDR
) {
485 rc
= sja1105_mdiobus_base_t1_register(priv
, mdio_node
);
487 goto err_free_base_tx_mdiobus
;
491 of_node_put(mdio_node
);
495 err_free_base_tx_mdiobus
:
496 sja1105_mdiobus_base_tx_unregister(priv
);
498 of_node_put(mdio_node
);
499 sja1105_mdiobus_pcs_unregister(priv
);
504 void sja1105_mdiobus_unregister(struct dsa_switch
*ds
)
506 struct sja1105_private
*priv
= ds
->priv
;
508 sja1105_mdiobus_base_t1_unregister(priv
);
509 sja1105_mdiobus_base_tx_unregister(priv
);
510 sja1105_mdiobus_pcs_unregister(priv
);