1
2
3
4
5
6#include <net/dsa.h>
7#include <dm/lists.h>
8#include <dm/device_compat.h>
9#include <dm/device-internal.h>
10#include <dm/uclass-internal.h>
11#include <linux/bitmap.h>
12#include <miiphy.h>
13
14#define DSA_PORT_CHILD_DRV_NAME "dsa-port"
15
16
17struct dsa_priv {
18 struct phy_device *cpu_port_fixed_phy;
19 struct udevice *master_dev;
20 int num_ports;
21 u32 cpu_port;
22 int headroom;
23 int tailroom;
24};
25
26
27int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom)
28{
29 struct dsa_priv *priv;
30
31 if (!dev)
32 return -EINVAL;
33
34 if (headroom + tailroom > DSA_MAX_OVR)
35 return -EINVAL;
36
37 priv = dev_get_uclass_priv(dev);
38
39 if (headroom > 0)
40 priv->headroom = headroom;
41 if (tailroom > 0)
42 priv->tailroom = tailroom;
43
44 return 0;
45}
46
47
48struct udevice *dsa_get_master(struct udevice *dev)
49{
50 struct dsa_priv *priv;
51
52 if (!dev)
53 return NULL;
54
55 priv = dev_get_uclass_priv(dev);
56
57 return priv->master_dev;
58}
59
60
61
62
63
64static int dsa_port_start(struct udevice *pdev)
65{
66 struct udevice *dev = dev_get_parent(pdev);
67 struct dsa_priv *priv = dev_get_uclass_priv(dev);
68 struct udevice *master = dsa_get_master(dev);
69 struct dsa_ops *ops = dsa_get_ops(dev);
70 int err;
71
72 if (ops->port_enable) {
73 struct dsa_port_pdata *port_pdata;
74
75 port_pdata = dev_get_parent_plat(pdev);
76 err = ops->port_enable(dev, port_pdata->index,
77 port_pdata->phy);
78 if (err)
79 return err;
80
81 err = ops->port_enable(dev, priv->cpu_port,
82 priv->cpu_port_fixed_phy);
83 if (err)
84 return err;
85 }
86
87 return eth_get_ops(master)->start(master);
88}
89
90
91static void dsa_port_stop(struct udevice *pdev)
92{
93 struct udevice *dev = dev_get_parent(pdev);
94 struct dsa_priv *priv = dev_get_uclass_priv(dev);
95 struct udevice *master = dsa_get_master(dev);
96 struct dsa_ops *ops = dsa_get_ops(dev);
97
98 if (ops->port_disable) {
99 struct dsa_port_pdata *port_pdata;
100
101 port_pdata = dev_get_parent_plat(pdev);
102 ops->port_disable(dev, port_pdata->index, port_pdata->phy);
103 ops->port_disable(dev, priv->cpu_port, priv->cpu_port_fixed_phy);
104 }
105
106 eth_get_ops(master)->stop(master);
107}
108
109
110
111
112
113
114static int dsa_port_send(struct udevice *pdev, void *packet, int length)
115{
116 struct udevice *dev = dev_get_parent(pdev);
117 struct dsa_priv *priv = dev_get_uclass_priv(dev);
118 int head = priv->headroom, tail = priv->tailroom;
119 struct udevice *master = dsa_get_master(dev);
120 struct dsa_ops *ops = dsa_get_ops(dev);
121 uchar dsa_packet_tmp[PKTSIZE_ALIGN];
122 struct dsa_port_pdata *port_pdata;
123 int err;
124
125 if (length + head + tail > PKTSIZE_ALIGN)
126 return -EINVAL;
127
128 memset(dsa_packet_tmp, 0, head);
129 memset(dsa_packet_tmp + head + length, 0, tail);
130 memcpy(dsa_packet_tmp + head, packet, length);
131 length += head + tail;
132
133 memcpy(packet, dsa_packet_tmp, length);
134
135 port_pdata = dev_get_parent_plat(pdev);
136 err = ops->xmit(dev, port_pdata->index, packet, length);
137 if (err)
138 return err;
139
140 return eth_get_ops(master)->send(master, packet, length);
141}
142
143
144static int dsa_port_recv(struct udevice *pdev, int flags, uchar **packetp)
145{
146 struct udevice *dev = dev_get_parent(pdev);
147 struct dsa_priv *priv = dev_get_uclass_priv(dev);
148 int head = priv->headroom, tail = priv->tailroom;
149 struct udevice *master = dsa_get_master(dev);
150 struct dsa_ops *ops = dsa_get_ops(dev);
151 struct dsa_port_pdata *port_pdata;
152 int length, port_index, err;
153
154 length = eth_get_ops(master)->recv(master, flags, packetp);
155 if (length <= 0)
156 return length;
157
158
159
160
161
162
163
164 port_pdata = dev_get_parent_plat(pdev);
165 err = ops->rcv(dev, &port_index, *packetp, length);
166 if (err || port_index != port_pdata->index || (length <= head + tail)) {
167 if (eth_get_ops(master)->free_pkt)
168 eth_get_ops(master)->free_pkt(master, *packetp, length);
169 return -EAGAIN;
170 }
171
172
173
174
175
176 *packetp += head;
177
178 return length - head - tail;
179}
180
181static int dsa_port_free_pkt(struct udevice *pdev, uchar *packet, int length)
182{
183 struct udevice *dev = dev_get_parent(pdev);
184 struct udevice *master = dsa_get_master(dev);
185 struct dsa_priv *priv;
186
187 priv = dev_get_uclass_priv(dev);
188 if (eth_get_ops(master)->free_pkt) {
189
190 packet -= priv->headroom;
191 length += priv->headroom - priv->tailroom;
192
193 return eth_get_ops(master)->free_pkt(master, packet, length);
194 }
195
196 return 0;
197}
198
199static int dsa_port_of_to_pdata(struct udevice *pdev)
200{
201 struct dsa_port_pdata *port_pdata;
202 struct eth_pdata *eth_pdata;
203 const char *label;
204 u32 index;
205 int err;
206
207 if (!pdev)
208 return -ENODEV;
209
210 err = ofnode_read_u32(dev_ofnode(pdev), "reg", &index);
211 if (err)
212 return err;
213
214 port_pdata = dev_get_parent_plat(pdev);
215 port_pdata->index = index;
216
217 label = ofnode_read_string(dev_ofnode(pdev), "label");
218 if (label)
219 strlcpy(port_pdata->name, label, DSA_PORT_NAME_LENGTH);
220
221 eth_pdata = dev_get_plat(pdev);
222 eth_pdata->priv_pdata = port_pdata;
223
224 dev_dbg(pdev, "port %d node %s\n", port_pdata->index,
225 ofnode_get_name(dev_ofnode(pdev)));
226
227 return 0;
228}
229
230static const struct eth_ops dsa_port_ops = {
231 .start = dsa_port_start,
232 .send = dsa_port_send,
233 .recv = dsa_port_recv,
234 .stop = dsa_port_stop,
235 .free_pkt = dsa_port_free_pkt,
236};
237
238
239
240
241
242static void dsa_port_set_hwaddr(struct udevice *pdev, struct udevice *master)
243{
244 struct eth_pdata *eth_pdata, *master_pdata;
245 unsigned char env_enetaddr[ARP_HLEN];
246
247 eth_env_get_enetaddr_by_index("eth", dev_seq(pdev), env_enetaddr);
248 if (!is_zero_ethaddr(env_enetaddr)) {
249
250 struct eth_ops *eth_ops = eth_get_ops(master);
251
252 if (eth_ops->set_promisc)
253 eth_ops->set_promisc(master, 1);
254
255 return;
256 }
257
258 master_pdata = dev_get_plat(master);
259 eth_pdata = dev_get_plat(pdev);
260 memcpy(eth_pdata->enetaddr, master_pdata->enetaddr, ARP_HLEN);
261 eth_env_set_enetaddr_by_index("eth", dev_seq(pdev),
262 master_pdata->enetaddr);
263}
264
265static int dsa_port_probe(struct udevice *pdev)
266{
267 struct udevice *dev = dev_get_parent(pdev);
268 struct dsa_ops *ops = dsa_get_ops(dev);
269 struct dsa_port_pdata *port_pdata;
270 struct udevice *master;
271 int err;
272
273 port_pdata = dev_get_parent_plat(pdev);
274
275 port_pdata->phy = dm_eth_phy_connect(pdev);
276 if (!port_pdata->phy)
277 return -ENODEV;
278
279 master = dsa_get_master(dev);
280 if (!master)
281 return -ENODEV;
282
283
284
285
286
287
288
289
290 err = device_probe(master);
291 if (err)
292 return err;
293
294 dsa_port_set_hwaddr(pdev, master);
295
296 if (ops->port_probe) {
297 err = ops->port_probe(dev, port_pdata->index,
298 port_pdata->phy);
299 if (err)
300 return err;
301 }
302
303 return 0;
304}
305
306static int dsa_port_remove(struct udevice *pdev)
307{
308 struct dsa_port_pdata *port_pdata = dev_get_parent_plat(pdev);
309
310 port_pdata->phy = NULL;
311
312 return 0;
313}
314
315U_BOOT_DRIVER(dsa_port) = {
316 .name = DSA_PORT_CHILD_DRV_NAME,
317 .id = UCLASS_ETH,
318 .ops = &dsa_port_ops,
319 .probe = dsa_port_probe,
320 .remove = dsa_port_remove,
321 .of_to_plat = dsa_port_of_to_pdata,
322 .plat_auto = sizeof(struct eth_pdata),
323};
324
325
326
327
328
329
330
331
332static int dsa_post_bind(struct udevice *dev)
333{
334 struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
335 ofnode node = dev_ofnode(dev), pnode;
336 int i, err, first_err = 0;
337
338 if (!ofnode_valid(node))
339 return -ENODEV;
340
341 pdata->master_node = ofnode_null();
342
343 node = ofnode_find_subnode(node, "ports");
344 if (!ofnode_valid(node))
345 node = ofnode_find_subnode(node, "ethernet-ports");
346 if (!ofnode_valid(node)) {
347 dev_err(dev, "ports node is missing under DSA device!\n");
348 return -EINVAL;
349 }
350
351 pdata->num_ports = ofnode_get_child_count(node);
352 if (pdata->num_ports <= 0 || pdata->num_ports > DSA_MAX_PORTS) {
353 dev_err(dev, "invalid number of ports (%d)\n",
354 pdata->num_ports);
355 return -EINVAL;
356 }
357
358
359 ofnode_for_each_subnode(pnode, node) {
360 u32 ethernet;
361
362 if (ofnode_read_u32(pnode, "ethernet", ðernet))
363 continue;
364
365 pdata->master_node = ofnode_get_by_phandle(ethernet);
366 pdata->cpu_port_node = pnode;
367 break;
368 }
369
370 if (!ofnode_valid(pdata->master_node)) {
371 dev_err(dev, "master eth node missing!\n");
372 return -EINVAL;
373 }
374
375 if (ofnode_read_u32(pnode, "reg", &pdata->cpu_port)) {
376 dev_err(dev, "CPU port node not valid!\n");
377 return -EINVAL;
378 }
379
380 dev_dbg(dev, "master node %s on port %d\n",
381 ofnode_get_name(pdata->master_node), pdata->cpu_port);
382
383 for (i = 0; i < pdata->num_ports; i++) {
384 char name[DSA_PORT_NAME_LENGTH];
385 struct udevice *pdev;
386
387
388
389
390
391
392 if (i == pdata->cpu_port)
393 continue;
394
395
396
397
398
399 snprintf(name, DSA_PORT_NAME_LENGTH, "%s@%d", dev->name, i);
400
401 ofnode_for_each_subnode(pnode, node) {
402 u32 reg;
403
404 if (ofnode_read_u32(pnode, "reg", ®))
405 continue;
406
407 if (reg == i)
408 break;
409 }
410
411
412
413
414
415 if (!ofnode_valid(pnode) || !ofnode_is_available(pnode))
416 continue;
417
418 err = device_bind_driver_to_node(dev, DSA_PORT_CHILD_DRV_NAME,
419 name, pnode, &pdev);
420 if (pdev) {
421 struct dsa_port_pdata *port_pdata;
422
423 port_pdata = dev_get_parent_plat(pdev);
424 strlcpy(port_pdata->name, name, DSA_PORT_NAME_LENGTH);
425 pdev->name = port_pdata->name;
426 }
427
428
429 if (err && !first_err)
430 first_err = err;
431 }
432
433 if (first_err)
434 return first_err;
435
436 dev_dbg(dev, "DSA ports successfully bound\n");
437
438 return 0;
439}
440
441
442
443
444
445static int dsa_pre_probe(struct udevice *dev)
446{
447 struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
448 struct dsa_priv *priv = dev_get_uclass_priv(dev);
449
450 priv->num_ports = pdata->num_ports;
451 priv->cpu_port = pdata->cpu_port;
452 priv->cpu_port_fixed_phy = fixed_phy_create(pdata->cpu_port_node);
453 if (!priv->cpu_port_fixed_phy) {
454 dev_err(dev, "Failed to register fixed-link for CPU port\n");
455 return -ENODEV;
456 }
457
458 uclass_find_device_by_ofnode(UCLASS_ETH, pdata->master_node,
459 &priv->master_dev);
460 return 0;
461}
462
463UCLASS_DRIVER(dsa) = {
464 .id = UCLASS_DSA,
465 .name = "dsa",
466 .post_bind = dsa_post_bind,
467 .pre_probe = dsa_pre_probe,
468 .per_device_auto = sizeof(struct dsa_priv),
469 .per_device_plat_auto = sizeof(struct dsa_pdata),
470 .per_child_plat_auto = sizeof(struct dsa_port_pdata),
471 .flags = DM_UC_FLAG_SEQ_ALIAS,
472};
473