Skip to content

Commit 5a8f097

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: sja1105: register the MDIO buses for 100base-T1 and 100base-TX
The SJA1110 contains two types of integrated PHYs: one 100base-TX PHY and multiple 100base-T1 PHYs. The access procedure for the 100base-T1 PHYs is also different than it is for the 100base-TX one. So we register 2 MDIO buses, one for the base-TX and the other for the base-T1. Each bus has an OF node which is a child of the "mdio" subnode of the switch, and they are recognized by compatible string. Cc: Russell King <[email protected]> Cc: Heiner Kallweit <[email protected]> Cc: Rob Herring <[email protected]> Cc: [email protected] Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ceec8bc commit 5a8f097

File tree

5 files changed

+358
-1
lines changed

5 files changed

+358
-1
lines changed

drivers/net/dsa/sja1105/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ obj-$(CONFIG_NET_DSA_SJA1105) += sja1105.o
44
sja1105-objs := \
55
sja1105_spi.o \
66
sja1105_main.o \
7+
sja1105_mdio.o \
78
sja1105_flower.o \
89
sja1105_ethtool.o \
910
sja1105_devlink.o \

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ struct sja1105_regs {
6767
u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
6868
u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
6969
u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
70+
u64 mdio_100base_tx;
71+
u64 mdio_100base_t1;
72+
};
73+
74+
struct sja1105_mdio_private {
75+
struct sja1105_private *priv;
7076
};
7177

7278
enum {
@@ -78,6 +84,12 @@ enum {
7884
SJA1105_SPEED_MAX,
7985
};
8086

87+
enum sja1105_internal_phy_t {
88+
SJA1105_NO_PHY = 0,
89+
SJA1105_PHY_BASE_TX,
90+
SJA1105_PHY_BASE_T1,
91+
};
92+
8193
struct sja1105_info {
8294
u64 device_id;
8395
/* Needed for distinction between P and R, and between Q and S
@@ -123,6 +135,7 @@ struct sja1105_info {
123135
bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
124136
bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
125137
bool supports_2500basex[SJA1105_MAX_NUM_PORTS];
138+
enum sja1105_internal_phy_t internal_phy[SJA1105_MAX_NUM_PORTS];
126139
const u64 port_speed[SJA1105_SPEED_MAX];
127140
};
128141

@@ -246,6 +259,8 @@ struct sja1105_private {
246259
enum sja1105_vlan_state vlan_state;
247260
struct devlink_region **regions;
248261
struct sja1105_cbs_entry *cbs;
262+
struct mii_bus *mdio_base_t1;
263+
struct mii_bus *mdio_base_tx;
249264
struct sja1105_tagger_data tagger_data;
250265
struct sja1105_ptp_data ptp_data;
251266
struct sja1105_tas_data tas_data;
@@ -275,6 +290,10 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
275290
struct netlink_ext_ack *extack);
276291
void sja1105_frame_memory_partitioning(struct sja1105_private *priv);
277292

293+
/* From sja1105_mdio.c */
294+
int sja1105_mdiobus_register(struct dsa_switch *ds);
295+
void sja1105_mdiobus_unregister(struct dsa_switch *ds);
296+
278297
/* From sja1105_devlink.c */
279298
int sja1105_devlink_setup(struct dsa_switch *ds);
280299
void sja1105_devlink_teardown(struct dsa_switch *ds);

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv)
168168
continue;
169169

170170
switch (priv->phy_mode[i]) {
171+
case PHY_INTERFACE_MODE_INTERNAL:
172+
if (priv->info->internal_phy[i] == SJA1105_NO_PHY)
173+
goto unsupported;
174+
175+
mii->xmii_mode[i] = XMII_MODE_MII;
176+
if (priv->info->internal_phy[i] == SJA1105_PHY_BASE_TX)
177+
mii->special[i] = true;
178+
179+
break;
171180
case PHY_INTERFACE_MODE_REVMII:
172181
role = XMII_PHY;
173182
fallthrough;
@@ -3109,11 +3118,19 @@ static int sja1105_setup(struct dsa_switch *ds)
31093118
dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc);
31103119
return rc;
31113120
}
3121+
3122+
rc = sja1105_mdiobus_register(ds);
3123+
if (rc < 0) {
3124+
dev_err(ds->dev, "Failed to register MDIO bus: %pe\n",
3125+
ERR_PTR(rc));
3126+
goto out_ptp_clock_unregister;
3127+
}
3128+
31123129
/* Create and send configuration down to device */
31133130
rc = sja1105_static_config_load(priv);
31143131
if (rc < 0) {
31153132
dev_err(ds->dev, "Failed to load static config: %d\n", rc);
3116-
goto out_ptp_clock_unregister;
3133+
goto out_mdiobus_unregister;
31173134
}
31183135
/* Configure the CGU (PHY link modes and speeds) */
31193136
rc = priv->info->clocking_setup(priv);
@@ -3156,6 +3173,8 @@ static int sja1105_setup(struct dsa_switch *ds)
31563173

31573174
out_devlink_teardown:
31583175
sja1105_devlink_teardown(ds);
3176+
out_mdiobus_unregister:
3177+
sja1105_mdiobus_unregister(ds);
31593178
out_ptp_clock_unregister:
31603179
sja1105_ptp_clock_unregister(ds);
31613180
out_static_config_free:
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright 2021, NXP Semiconductors
3+
*/
4+
#include <linux/of_mdio.h>
5+
#include "sja1105.h"
6+
7+
enum sja1105_mdio_opcode {
8+
SJA1105_C45_ADDR = 0,
9+
SJA1105_C22 = 1,
10+
SJA1105_C45_DATA = 2,
11+
SJA1105_C45_DATA_AUTOINC = 3,
12+
};
13+
14+
static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,
15+
int phy, enum sja1105_mdio_opcode op,
16+
int xad)
17+
{
18+
const struct sja1105_regs *regs = priv->info->regs;
19+
20+
return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);
21+
}
22+
23+
static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg)
24+
{
25+
struct sja1105_mdio_private *mdio_priv = bus->priv;
26+
struct sja1105_private *priv = mdio_priv->priv;
27+
u64 addr;
28+
u32 tmp;
29+
int rc;
30+
31+
if (reg & MII_ADDR_C45) {
32+
u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
33+
34+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
35+
mmd);
36+
37+
tmp = reg & MII_REGADDR_C45_MASK;
38+
39+
rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
40+
if (rc < 0)
41+
return rc;
42+
43+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
44+
mmd);
45+
46+
rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
47+
if (rc < 0)
48+
return rc;
49+
50+
return tmp & 0xffff;
51+
}
52+
53+
/* Clause 22 read */
54+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
55+
56+
rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
57+
if (rc < 0)
58+
return rc;
59+
60+
return tmp & 0xffff;
61+
}
62+
63+
static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg,
64+
u16 val)
65+
{
66+
struct sja1105_mdio_private *mdio_priv = bus->priv;
67+
struct sja1105_private *priv = mdio_priv->priv;
68+
u64 addr;
69+
u32 tmp;
70+
int rc;
71+
72+
if (reg & MII_ADDR_C45) {
73+
u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
74+
75+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
76+
mmd);
77+
78+
tmp = reg & MII_REGADDR_C45_MASK;
79+
80+
rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
81+
if (rc < 0)
82+
return rc;
83+
84+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
85+
mmd);
86+
87+
tmp = val & 0xffff;
88+
89+
rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
90+
if (rc < 0)
91+
return rc;
92+
93+
return 0;
94+
}
95+
96+
/* Clause 22 write */
97+
addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
98+
99+
tmp = val & 0xffff;
100+
101+
return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
102+
}
103+
104+
static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
105+
{
106+
struct sja1105_mdio_private *mdio_priv = bus->priv;
107+
struct sja1105_private *priv = mdio_priv->priv;
108+
const struct sja1105_regs *regs = priv->info->regs;
109+
u32 tmp;
110+
int rc;
111+
112+
rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
113+
&tmp, NULL);
114+
if (rc < 0)
115+
return rc;
116+
117+
return tmp & 0xffff;
118+
}
119+
120+
static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
121+
u16 val)
122+
{
123+
struct sja1105_mdio_private *mdio_priv = bus->priv;
124+
struct sja1105_private *priv = mdio_priv->priv;
125+
const struct sja1105_regs *regs = priv->info->regs;
126+
u32 tmp = val;
127+
128+
return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
129+
&tmp, NULL);
130+
}
131+
132+
static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
133+
struct device_node *mdio_node)
134+
{
135+
struct sja1105_mdio_private *mdio_priv;
136+
struct device_node *np;
137+
struct mii_bus *bus;
138+
int rc = 0;
139+
140+
np = of_find_compatible_node(mdio_node, NULL,
141+
"nxp,sja1110-base-tx-mdio");
142+
if (!np)
143+
return 0;
144+
145+
if (!of_device_is_available(np))
146+
goto out_put_np;
147+
148+
bus = mdiobus_alloc_size(sizeof(*mdio_priv));
149+
if (!bus) {
150+
rc = -ENOMEM;
151+
goto out_put_np;
152+
}
153+
154+
bus->name = "SJA1110 100base-TX MDIO bus";
155+
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
156+
dev_name(priv->ds->dev));
157+
bus->read = sja1105_base_tx_mdio_read;
158+
bus->write = sja1105_base_tx_mdio_write;
159+
bus->parent = priv->ds->dev;
160+
mdio_priv = bus->priv;
161+
mdio_priv->priv = priv;
162+
163+
rc = of_mdiobus_register(bus, np);
164+
if (rc) {
165+
mdiobus_free(bus);
166+
goto out_put_np;
167+
}
168+
169+
priv->mdio_base_tx = bus;
170+
171+
out_put_np:
172+
of_node_put(np);
173+
174+
return 0;
175+
}
176+
177+
static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
178+
{
179+
if (!priv->mdio_base_tx)
180+
return;
181+
182+
mdiobus_unregister(priv->mdio_base_tx);
183+
mdiobus_free(priv->mdio_base_tx);
184+
priv->mdio_base_tx = NULL;
185+
}
186+
187+
static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
188+
struct device_node *mdio_node)
189+
{
190+
struct sja1105_mdio_private *mdio_priv;
191+
struct device_node *np;
192+
struct mii_bus *bus;
193+
int rc = 0;
194+
195+
np = of_find_compatible_node(mdio_node, NULL,
196+
"nxp,sja1110-base-t1-mdio");
197+
if (!np)
198+
return 0;
199+
200+
if (!of_device_is_available(np))
201+
goto out_put_np;
202+
203+
bus = mdiobus_alloc_size(sizeof(*mdio_priv));
204+
if (!bus) {
205+
rc = -ENOMEM;
206+
goto out_put_np;
207+
}
208+
209+
bus->name = "SJA1110 100base-T1 MDIO bus";
210+
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
211+
dev_name(priv->ds->dev));
212+
bus->read = sja1105_base_t1_mdio_read;
213+
bus->write = sja1105_base_t1_mdio_write;
214+
bus->parent = priv->ds->dev;
215+
mdio_priv = bus->priv;
216+
mdio_priv->priv = priv;
217+
218+
rc = of_mdiobus_register(bus, np);
219+
if (rc) {
220+
mdiobus_free(bus);
221+
goto out_put_np;
222+
}
223+
224+
priv->mdio_base_t1 = bus;
225+
226+
out_put_np:
227+
of_node_put(np);
228+
229+
return rc;
230+
}
231+
232+
static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
233+
{
234+
if (!priv->mdio_base_t1)
235+
return;
236+
237+
mdiobus_unregister(priv->mdio_base_t1);
238+
mdiobus_free(priv->mdio_base_t1);
239+
priv->mdio_base_t1 = NULL;
240+
}
241+
242+
int sja1105_mdiobus_register(struct dsa_switch *ds)
243+
{
244+
struct sja1105_private *priv = ds->priv;
245+
const struct sja1105_regs *regs = priv->info->regs;
246+
struct device_node *switch_node = ds->dev->of_node;
247+
struct device_node *mdio_node;
248+
int rc;
249+
250+
mdio_node = of_get_child_by_name(switch_node, "mdios");
251+
if (!mdio_node)
252+
return 0;
253+
254+
if (!of_device_is_available(mdio_node))
255+
goto out_put_mdio_node;
256+
257+
if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
258+
rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
259+
if (rc)
260+
goto err_put_mdio_node;
261+
}
262+
263+
if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
264+
rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
265+
if (rc)
266+
goto err_free_base_tx_mdiobus;
267+
}
268+
269+
out_put_mdio_node:
270+
of_node_put(mdio_node);
271+
272+
return 0;
273+
274+
err_free_base_tx_mdiobus:
275+
sja1105_mdiobus_base_tx_unregister(priv);
276+
err_put_mdio_node:
277+
of_node_put(mdio_node);
278+
279+
return rc;
280+
}
281+
282+
void sja1105_mdiobus_unregister(struct dsa_switch *ds)
283+
{
284+
struct sja1105_private *priv = ds->priv;
285+
286+
sja1105_mdiobus_base_t1_unregister(priv);
287+
sja1105_mdiobus_base_tx_unregister(priv);
288+
}

0 commit comments

Comments
 (0)