xref: /linux/drivers/net/dsa/sja1105/sja1105_mdio.c (revision e83332842a46c091992ad06145b5c1b65a08ab05)
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 }
289