Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2022 Schneider-Electric
4 *
5 * Clément Léger <clement.leger@bootlin.com>
6 */
7
8#include <linux/clk.h>
9#include <linux/etherdevice.h>
10#include <linux/if_bridge.h>
11#include <linux/if_ether.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_mdio.h>
16#include <net/dsa.h>
17
18#include "rzn1_a5psw.h"
19
20struct a5psw_stats {
21 u16 offset;
22 const char name[ETH_GSTRING_LEN];
23};
24
25#define STAT_DESC(_offset) { \
26 .offset = A5PSW_##_offset, \
27 .name = __stringify(_offset), \
28}
29
30static const struct a5psw_stats a5psw_stats[] = {
31 STAT_DESC(aFramesTransmittedOK),
32 STAT_DESC(aFramesReceivedOK),
33 STAT_DESC(aFrameCheckSequenceErrors),
34 STAT_DESC(aAlignmentErrors),
35 STAT_DESC(aOctetsTransmittedOK),
36 STAT_DESC(aOctetsReceivedOK),
37 STAT_DESC(aTxPAUSEMACCtrlFrames),
38 STAT_DESC(aRxPAUSEMACCtrlFrames),
39 STAT_DESC(ifInErrors),
40 STAT_DESC(ifOutErrors),
41 STAT_DESC(ifInUcastPkts),
42 STAT_DESC(ifInMulticastPkts),
43 STAT_DESC(ifInBroadcastPkts),
44 STAT_DESC(ifOutDiscards),
45 STAT_DESC(ifOutUcastPkts),
46 STAT_DESC(ifOutMulticastPkts),
47 STAT_DESC(ifOutBroadcastPkts),
48 STAT_DESC(etherStatsDropEvents),
49 STAT_DESC(etherStatsOctets),
50 STAT_DESC(etherStatsPkts),
51 STAT_DESC(etherStatsUndersizePkts),
52 STAT_DESC(etherStatsOversizePkts),
53 STAT_DESC(etherStatsPkts64Octets),
54 STAT_DESC(etherStatsPkts65to127Octets),
55 STAT_DESC(etherStatsPkts128to255Octets),
56 STAT_DESC(etherStatsPkts256to511Octets),
57 STAT_DESC(etherStatsPkts1024to1518Octets),
58 STAT_DESC(etherStatsPkts1519toXOctets),
59 STAT_DESC(etherStatsJabbers),
60 STAT_DESC(etherStatsFragments),
61 STAT_DESC(VLANReceived),
62 STAT_DESC(VLANTransmitted),
63 STAT_DESC(aDeferred),
64 STAT_DESC(aMultipleCollisions),
65 STAT_DESC(aSingleCollisions),
66 STAT_DESC(aLateCollisions),
67 STAT_DESC(aExcessiveCollisions),
68 STAT_DESC(aCarrierSenseErrors),
69};
70
71static void a5psw_reg_writel(struct a5psw *a5psw, int offset, u32 value)
72{
73 writel(value, a5psw->base + offset);
74}
75
76static u32 a5psw_reg_readl(struct a5psw *a5psw, int offset)
77{
78 return readl(a5psw->base + offset);
79}
80
81static void a5psw_reg_rmw(struct a5psw *a5psw, int offset, u32 mask, u32 val)
82{
83 u32 reg;
84
85 spin_lock(&a5psw->reg_lock);
86
87 reg = a5psw_reg_readl(a5psw, offset);
88 reg &= ~mask;
89 reg |= val;
90 a5psw_reg_writel(a5psw, offset, reg);
91
92 spin_unlock(&a5psw->reg_lock);
93}
94
95static enum dsa_tag_protocol a5psw_get_tag_protocol(struct dsa_switch *ds,
96 int port,
97 enum dsa_tag_protocol mp)
98{
99 return DSA_TAG_PROTO_RZN1_A5PSW;
100}
101
102static void a5psw_port_pattern_set(struct a5psw *a5psw, int port, int pattern,
103 bool enable)
104{
105 u32 rx_match = 0;
106
107 if (enable)
108 rx_match |= A5PSW_RXMATCH_CONFIG_PATTERN(pattern);
109
110 a5psw_reg_rmw(a5psw, A5PSW_RXMATCH_CONFIG(port),
111 A5PSW_RXMATCH_CONFIG_PATTERN(pattern), rx_match);
112}
113
114static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable)
115{
116 /* Enable "management forward" pattern matching, this will forward
117 * packets from this port only towards the management port and thus
118 * isolate the port.
119 */
120 a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable);
121}
122
123static void a5psw_port_tx_enable(struct a5psw *a5psw, int port, bool enable)
124{
125 u32 mask = A5PSW_PORT_ENA_TX(port);
126 u32 reg = enable ? mask : 0;
127
128 /* Even though the port TX is disabled through TXENA bit in the
129 * PORT_ENA register, it can still send BPDUs. This depends on the tag
130 * configuration added when sending packets from the CPU port to the
131 * switch port. Indeed, when using forced forwarding without filtering,
132 * even disabled ports will be able to send packets that are tagged.
133 * This allows to implement STP support when ports are in a state where
134 * forwarding traffic should be stopped but BPDUs should still be sent.
135 */
136 a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, mask, reg);
137}
138
139static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable)
140{
141 u32 port_ena = 0;
142
143 if (enable)
144 port_ena |= A5PSW_PORT_ENA_TX_RX(port);
145
146 a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, A5PSW_PORT_ENA_TX_RX(port),
147 port_ena);
148}
149
150static int a5psw_lk_execute_ctrl(struct a5psw *a5psw, u32 *ctrl)
151{
152 int ret;
153
154 a5psw_reg_writel(a5psw, A5PSW_LK_ADDR_CTRL, *ctrl);
155
156 ret = readl_poll_timeout(a5psw->base + A5PSW_LK_ADDR_CTRL, *ctrl,
157 !(*ctrl & A5PSW_LK_ADDR_CTRL_BUSY),
158 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
159 if (ret)
160 dev_err(a5psw->dev, "LK_CTRL timeout waiting for BUSY bit\n");
161
162 return ret;
163}
164
165static void a5psw_port_fdb_flush(struct a5psw *a5psw, int port)
166{
167 u32 ctrl = A5PSW_LK_ADDR_CTRL_DELETE_PORT | BIT(port);
168
169 mutex_lock(&a5psw->lk_lock);
170 a5psw_lk_execute_ctrl(a5psw, &ctrl);
171 mutex_unlock(&a5psw->lk_lock);
172}
173
174static void a5psw_port_authorize_set(struct a5psw *a5psw, int port,
175 bool authorize)
176{
177 u32 reg = a5psw_reg_readl(a5psw, A5PSW_AUTH_PORT(port));
178
179 if (authorize)
180 reg |= A5PSW_AUTH_PORT_AUTHORIZED;
181 else
182 reg &= ~A5PSW_AUTH_PORT_AUTHORIZED;
183
184 a5psw_reg_writel(a5psw, A5PSW_AUTH_PORT(port), reg);
185}
186
187static void a5psw_port_disable(struct dsa_switch *ds, int port)
188{
189 struct a5psw *a5psw = ds->priv;
190
191 a5psw_port_authorize_set(a5psw, port, false);
192 a5psw_port_enable_set(a5psw, port, false);
193}
194
195static int a5psw_port_enable(struct dsa_switch *ds, int port,
196 struct phy_device *phy)
197{
198 struct a5psw *a5psw = ds->priv;
199
200 a5psw_port_authorize_set(a5psw, port, true);
201 a5psw_port_enable_set(a5psw, port, true);
202
203 return 0;
204}
205
206static int a5psw_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
207{
208 struct a5psw *a5psw = ds->priv;
209
210 new_mtu += ETH_HLEN + A5PSW_EXTRA_MTU_LEN + ETH_FCS_LEN;
211 a5psw_reg_writel(a5psw, A5PSW_FRM_LENGTH(port), new_mtu);
212
213 return 0;
214}
215
216static int a5psw_port_max_mtu(struct dsa_switch *ds, int port)
217{
218 return A5PSW_MAX_MTU;
219}
220
221static void a5psw_phylink_get_caps(struct dsa_switch *ds, int port,
222 struct phylink_config *config)
223{
224 unsigned long *intf = config->supported_interfaces;
225
226 config->mac_capabilities = MAC_1000FD;
227
228 if (dsa_is_cpu_port(ds, port)) {
229 /* GMII is used internally and GMAC2 is connected to the switch
230 * using 1000Mbps Full-Duplex mode only (cf ethernet manual)
231 */
232 __set_bit(PHY_INTERFACE_MODE_GMII, intf);
233 } else {
234 config->mac_capabilities |= MAC_100 | MAC_10;
235 phy_interface_set_rgmii(intf);
236 __set_bit(PHY_INTERFACE_MODE_RMII, intf);
237 __set_bit(PHY_INTERFACE_MODE_MII, intf);
238 }
239}
240
241static struct phylink_pcs *
242a5psw_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
243 phy_interface_t interface)
244{
245 struct dsa_port *dp = dsa_to_port(ds, port);
246 struct a5psw *a5psw = ds->priv;
247
248 if (!dsa_port_is_cpu(dp) && a5psw->pcs[port])
249 return a5psw->pcs[port];
250
251 return NULL;
252}
253
254static void a5psw_phylink_mac_link_down(struct dsa_switch *ds, int port,
255 unsigned int mode,
256 phy_interface_t interface)
257{
258 struct a5psw *a5psw = ds->priv;
259 u32 cmd_cfg;
260
261 cmd_cfg = a5psw_reg_readl(a5psw, A5PSW_CMD_CFG(port));
262 cmd_cfg &= ~(A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA);
263 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
264}
265
266static void a5psw_phylink_mac_link_up(struct dsa_switch *ds, int port,
267 unsigned int mode,
268 phy_interface_t interface,
269 struct phy_device *phydev, int speed,
270 int duplex, bool tx_pause, bool rx_pause)
271{
272 u32 cmd_cfg = A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA |
273 A5PSW_CMD_CFG_TX_CRC_APPEND;
274 struct a5psw *a5psw = ds->priv;
275
276 if (speed == SPEED_1000)
277 cmd_cfg |= A5PSW_CMD_CFG_ETH_SPEED;
278
279 if (duplex == DUPLEX_HALF)
280 cmd_cfg |= A5PSW_CMD_CFG_HD_ENA;
281
282 cmd_cfg |= A5PSW_CMD_CFG_CNTL_FRM_ENA;
283
284 if (!rx_pause)
285 cmd_cfg &= ~A5PSW_CMD_CFG_PAUSE_IGNORE;
286
287 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
288}
289
290static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
291{
292 struct a5psw *a5psw = ds->priv;
293 unsigned long rate;
294 u64 max, tmp;
295 u32 agetime;
296
297 rate = clk_get_rate(a5psw->clk);
298 max = div64_ul(((u64)A5PSW_LK_AGETIME_MASK * A5PSW_TABLE_ENTRIES * 1024),
299 rate) * 1000;
300 if (msecs > max)
301 return -EINVAL;
302
303 tmp = div_u64(rate, MSEC_PER_SEC);
304 agetime = div_u64(msecs * tmp, 1024 * A5PSW_TABLE_ENTRIES);
305
306 a5psw_reg_writel(a5psw, A5PSW_LK_AGETIME, agetime);
307
308 return 0;
309}
310
311static void a5psw_port_learning_set(struct a5psw *a5psw, int port, bool learn)
312{
313 u32 mask = A5PSW_INPUT_LEARN_DIS(port);
314 u32 reg = !learn ? mask : 0;
315
316 a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
317}
318
319static void a5psw_port_rx_block_set(struct a5psw *a5psw, int port, bool block)
320{
321 u32 mask = A5PSW_INPUT_LEARN_BLOCK(port);
322 u32 reg = block ? mask : 0;
323
324 a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
325}
326
327static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
328 bool set)
329{
330 u8 offsets[] = {A5PSW_UCAST_DEF_MASK, A5PSW_BCAST_DEF_MASK,
331 A5PSW_MCAST_DEF_MASK};
332 int i;
333
334 for (i = 0; i < ARRAY_SIZE(offsets); i++)
335 a5psw_reg_rmw(a5psw, offsets[i], BIT(port),
336 set ? BIT(port) : 0);
337}
338
339static void a5psw_port_set_standalone(struct a5psw *a5psw, int port,
340 bool standalone)
341{
342 a5psw_port_learning_set(a5psw, port, !standalone);
343 a5psw_flooding_set_resolution(a5psw, port, !standalone);
344 a5psw_port_mgmtfwd_set(a5psw, port, standalone);
345}
346
347static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
348 struct dsa_bridge bridge,
349 bool *tx_fwd_offload,
350 struct netlink_ext_ack *extack)
351{
352 struct a5psw *a5psw = ds->priv;
353
354 /* We only support 1 bridge device */
355 if (a5psw->br_dev && bridge.dev != a5psw->br_dev) {
356 NL_SET_ERR_MSG_MOD(extack,
357 "Forwarding offload supported for a single bridge");
358 return -EOPNOTSUPP;
359 }
360
361 a5psw->br_dev = bridge.dev;
362 a5psw_port_set_standalone(a5psw, port, false);
363
364 a5psw->bridged_ports |= BIT(port);
365
366 return 0;
367}
368
369static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
370 struct dsa_bridge bridge)
371{
372 struct a5psw *a5psw = ds->priv;
373
374 a5psw->bridged_ports &= ~BIT(port);
375
376 a5psw_port_set_standalone(a5psw, port, true);
377
378 /* No more ports bridged */
379 if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT))
380 a5psw->br_dev = NULL;
381}
382
383static int a5psw_port_pre_bridge_flags(struct dsa_switch *ds, int port,
384 struct switchdev_brport_flags flags,
385 struct netlink_ext_ack *extack)
386{
387 if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
388 BR_BCAST_FLOOD))
389 return -EINVAL;
390
391 return 0;
392}
393
394static int
395a5psw_port_bridge_flags(struct dsa_switch *ds, int port,
396 struct switchdev_brport_flags flags,
397 struct netlink_ext_ack *extack)
398{
399 struct a5psw *a5psw = ds->priv;
400 u32 val;
401
402 /* If a port is set as standalone, we do not want to be able to
403 * configure flooding nor learning which would result in joining the
404 * unique bridge. This can happen when a port leaves the bridge, in
405 * which case the DSA core will try to "clear" all flags for the
406 * standalone port (ie enable flooding, disable learning). In that case
407 * do not fail but do not apply the flags.
408 */
409 if (!(a5psw->bridged_ports & BIT(port)))
410 return 0;
411
412 if (flags.mask & BR_LEARNING) {
413 val = flags.val & BR_LEARNING ? 0 : A5PSW_INPUT_LEARN_DIS(port);
414 a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN,
415 A5PSW_INPUT_LEARN_DIS(port), val);
416 }
417
418 if (flags.mask & BR_FLOOD) {
419 val = flags.val & BR_FLOOD ? BIT(port) : 0;
420 a5psw_reg_rmw(a5psw, A5PSW_UCAST_DEF_MASK, BIT(port), val);
421 }
422
423 if (flags.mask & BR_MCAST_FLOOD) {
424 val = flags.val & BR_MCAST_FLOOD ? BIT(port) : 0;
425 a5psw_reg_rmw(a5psw, A5PSW_MCAST_DEF_MASK, BIT(port), val);
426 }
427
428 if (flags.mask & BR_BCAST_FLOOD) {
429 val = flags.val & BR_BCAST_FLOOD ? BIT(port) : 0;
430 a5psw_reg_rmw(a5psw, A5PSW_BCAST_DEF_MASK, BIT(port), val);
431 }
432
433 return 0;
434}
435
436static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
437{
438 bool learning_enabled, rx_enabled, tx_enabled;
439 struct dsa_port *dp = dsa_to_port(ds, port);
440 struct a5psw *a5psw = ds->priv;
441
442 switch (state) {
443 case BR_STATE_DISABLED:
444 case BR_STATE_BLOCKING:
445 case BR_STATE_LISTENING:
446 rx_enabled = false;
447 tx_enabled = false;
448 learning_enabled = false;
449 break;
450 case BR_STATE_LEARNING:
451 rx_enabled = false;
452 tx_enabled = false;
453 learning_enabled = dp->learning;
454 break;
455 case BR_STATE_FORWARDING:
456 rx_enabled = true;
457 tx_enabled = true;
458 learning_enabled = dp->learning;
459 break;
460 default:
461 dev_err(ds->dev, "invalid STP state: %d\n", state);
462 return;
463 }
464
465 a5psw_port_learning_set(a5psw, port, learning_enabled);
466 a5psw_port_rx_block_set(a5psw, port, !rx_enabled);
467 a5psw_port_tx_enable(a5psw, port, tx_enabled);
468}
469
470static void a5psw_port_fast_age(struct dsa_switch *ds, int port)
471{
472 struct a5psw *a5psw = ds->priv;
473
474 a5psw_port_fdb_flush(a5psw, port);
475}
476
477static int a5psw_lk_execute_lookup(struct a5psw *a5psw, union lk_data *lk_data,
478 u16 *entry)
479{
480 u32 ctrl;
481 int ret;
482
483 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_LO, lk_data->lo);
484 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data->hi);
485
486 ctrl = A5PSW_LK_ADDR_CTRL_LOOKUP;
487 ret = a5psw_lk_execute_ctrl(a5psw, &ctrl);
488 if (ret)
489 return ret;
490
491 *entry = ctrl & A5PSW_LK_ADDR_CTRL_ADDRESS;
492
493 return 0;
494}
495
496static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
497 const unsigned char *addr, u16 vid,
498 struct dsa_db db)
499{
500 struct a5psw *a5psw = ds->priv;
501 union lk_data lk_data = {0};
502 bool inc_learncount = false;
503 int ret = 0;
504 u16 entry;
505 u32 reg;
506
507 ether_addr_copy(lk_data.entry.mac, addr);
508 lk_data.entry.port_mask = BIT(port);
509
510 mutex_lock(&a5psw->lk_lock);
511
512 /* Set the value to be written in the lookup table */
513 ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
514 if (ret)
515 goto lk_unlock;
516
517 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
518 if (!lk_data.entry.valid) {
519 inc_learncount = true;
520 /* port_mask set to 0x1f when entry is not valid, clear it */
521 lk_data.entry.port_mask = 0;
522 lk_data.entry.prio = 0;
523 }
524
525 lk_data.entry.port_mask |= BIT(port);
526 lk_data.entry.is_static = 1;
527 lk_data.entry.valid = 1;
528
529 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
530
531 reg = A5PSW_LK_ADDR_CTRL_WRITE | entry;
532 ret = a5psw_lk_execute_ctrl(a5psw, ®);
533 if (ret)
534 goto lk_unlock;
535
536 if (inc_learncount) {
537 reg = A5PSW_LK_LEARNCOUNT_MODE_INC;
538 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
539 }
540
541lk_unlock:
542 mutex_unlock(&a5psw->lk_lock);
543
544 return ret;
545}
546
547static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
548 const unsigned char *addr, u16 vid,
549 struct dsa_db db)
550{
551 struct a5psw *a5psw = ds->priv;
552 union lk_data lk_data = {0};
553 bool clear = false;
554 u16 entry;
555 u32 reg;
556 int ret;
557
558 ether_addr_copy(lk_data.entry.mac, addr);
559
560 mutex_lock(&a5psw->lk_lock);
561
562 ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
563 if (ret)
564 goto lk_unlock;
565
566 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
567
568 /* Our hardware does not associate any VID to the FDB entries so this
569 * means that if two entries were added for the same mac but for
570 * different VID, then, on the deletion of the first one, we would also
571 * delete the second one. Since there is unfortunately nothing we can do
572 * about that, do not return an error...
573 */
574 if (!lk_data.entry.valid)
575 goto lk_unlock;
576
577 lk_data.entry.port_mask &= ~BIT(port);
578 /* If there is no more port in the mask, clear the entry */
579 if (lk_data.entry.port_mask == 0)
580 clear = true;
581
582 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
583
584 reg = entry;
585 if (clear)
586 reg |= A5PSW_LK_ADDR_CTRL_CLEAR;
587 else
588 reg |= A5PSW_LK_ADDR_CTRL_WRITE;
589
590 ret = a5psw_lk_execute_ctrl(a5psw, ®);
591 if (ret)
592 goto lk_unlock;
593
594 /* Decrement LEARNCOUNT */
595 if (clear) {
596 reg = A5PSW_LK_LEARNCOUNT_MODE_DEC;
597 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
598 }
599
600lk_unlock:
601 mutex_unlock(&a5psw->lk_lock);
602
603 return ret;
604}
605
606static int a5psw_port_fdb_dump(struct dsa_switch *ds, int port,
607 dsa_fdb_dump_cb_t *cb, void *data)
608{
609 struct a5psw *a5psw = ds->priv;
610 union lk_data lk_data;
611 int i = 0, ret = 0;
612 u32 reg;
613
614 mutex_lock(&a5psw->lk_lock);
615
616 for (i = 0; i < A5PSW_TABLE_ENTRIES; i++) {
617 reg = A5PSW_LK_ADDR_CTRL_READ | A5PSW_LK_ADDR_CTRL_WAIT | i;
618
619 ret = a5psw_lk_execute_ctrl(a5psw, ®);
620 if (ret)
621 goto out_unlock;
622
623 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
624 /* If entry is not valid or does not contain the port, skip */
625 if (!lk_data.entry.valid ||
626 !(lk_data.entry.port_mask & BIT(port)))
627 continue;
628
629 lk_data.lo = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_LO);
630
631 ret = cb(lk_data.entry.mac, 0, lk_data.entry.is_static, data);
632 if (ret)
633 goto out_unlock;
634 }
635
636out_unlock:
637 mutex_unlock(&a5psw->lk_lock);
638
639 return ret;
640}
641
642static int a5psw_port_vlan_filtering(struct dsa_switch *ds, int port,
643 bool vlan_filtering,
644 struct netlink_ext_ack *extack)
645{
646 u32 mask = BIT(port + A5PSW_VLAN_VERI_SHIFT) |
647 BIT(port + A5PSW_VLAN_DISC_SHIFT);
648 u32 val = vlan_filtering ? mask : 0;
649 struct a5psw *a5psw = ds->priv;
650
651 /* Disable/enable vlan tagging */
652 a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE_ENA, BIT(port),
653 vlan_filtering ? BIT(port) : 0);
654
655 /* Disable/enable vlan input filtering */
656 a5psw_reg_rmw(a5psw, A5PSW_VLAN_VERIFY, mask, val);
657
658 return 0;
659}
660
661static int a5psw_find_vlan_entry(struct a5psw *a5psw, u16 vid)
662{
663 u32 vlan_res;
664 int i;
665
666 /* Find vlan for this port */
667 for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
668 vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
669 if (FIELD_GET(A5PSW_VLAN_RES_VLANID, vlan_res) == vid)
670 return i;
671 }
672
673 return -1;
674}
675
676static int a5psw_new_vlan_res_entry(struct a5psw *a5psw, u16 newvid)
677{
678 u32 vlan_res;
679 int i;
680
681 /* Find a free VLAN entry */
682 for (i = 0; i < A5PSW_VLAN_COUNT; i++) {
683 vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i));
684 if (!(FIELD_GET(A5PSW_VLAN_RES_PORTMASK, vlan_res))) {
685 vlan_res = FIELD_PREP(A5PSW_VLAN_RES_VLANID, newvid);
686 a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(i), vlan_res);
687 return i;
688 }
689 }
690
691 return -1;
692}
693
694static void a5psw_port_vlan_tagged_cfg(struct a5psw *a5psw,
695 unsigned int vlan_res_id, int port,
696 bool set)
697{
698 u32 mask = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_RD_TAGMASK |
699 BIT(port);
700 u32 vlan_res_off = A5PSW_VLAN_RES(vlan_res_id);
701 u32 val = A5PSW_VLAN_RES_WR_TAGMASK, reg;
702
703 if (set)
704 val |= BIT(port);
705
706 /* Toggle tag mask read */
707 a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
708 reg = a5psw_reg_readl(a5psw, vlan_res_off);
709 a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK);
710
711 reg &= ~mask;
712 reg |= val;
713 a5psw_reg_writel(a5psw, vlan_res_off, reg);
714}
715
716static void a5psw_port_vlan_cfg(struct a5psw *a5psw, unsigned int vlan_res_id,
717 int port, bool set)
718{
719 u32 mask = A5PSW_VLAN_RES_WR_TAGMASK | BIT(port);
720 u32 reg = A5PSW_VLAN_RES_WR_PORTMASK;
721
722 if (set)
723 reg |= BIT(port);
724
725 a5psw_reg_rmw(a5psw, A5PSW_VLAN_RES(vlan_res_id), mask, reg);
726}
727
728static int a5psw_port_vlan_add(struct dsa_switch *ds, int port,
729 const struct switchdev_obj_port_vlan *vlan,
730 struct netlink_ext_ack *extack)
731{
732 bool tagged = !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
733 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
734 struct a5psw *a5psw = ds->priv;
735 u16 vid = vlan->vid;
736 int vlan_res_id;
737
738 vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
739 if (vlan_res_id < 0) {
740 vlan_res_id = a5psw_new_vlan_res_entry(a5psw, vid);
741 if (vlan_res_id < 0)
742 return -ENOSPC;
743 }
744
745 a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, true);
746 if (tagged)
747 a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, true);
748
749 /* Configure port to tag with corresponding VID, but do not enable it
750 * yet: wait for vlan filtering to be enabled to enable vlan port
751 * tagging
752 */
753 if (pvid)
754 a5psw_reg_writel(a5psw, A5PSW_SYSTEM_TAGINFO(port), vid);
755
756 return 0;
757}
758
759static int a5psw_port_vlan_del(struct dsa_switch *ds, int port,
760 const struct switchdev_obj_port_vlan *vlan)
761{
762 struct a5psw *a5psw = ds->priv;
763 u16 vid = vlan->vid;
764 int vlan_res_id;
765
766 vlan_res_id = a5psw_find_vlan_entry(a5psw, vid);
767 if (vlan_res_id < 0)
768 return -EINVAL;
769
770 a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, false);
771 a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, false);
772
773 return 0;
774}
775
776static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port)
777{
778 u32 reg_lo, reg_hi;
779
780 reg_lo = a5psw_reg_readl(a5psw, offset + A5PSW_PORT_OFFSET(port));
781 /* A5PSW_STATS_HIWORD is latched on stat read */
782 reg_hi = a5psw_reg_readl(a5psw, A5PSW_STATS_HIWORD);
783
784 return ((u64)reg_hi << 32) | reg_lo;
785}
786
787static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset,
788 uint8_t *data)
789{
790 unsigned int u;
791
792 if (stringset != ETH_SS_STATS)
793 return;
794
795 for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) {
796 memcpy(data + u * ETH_GSTRING_LEN, a5psw_stats[u].name,
797 ETH_GSTRING_LEN);
798 }
799}
800
801static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port,
802 uint64_t *data)
803{
804 struct a5psw *a5psw = ds->priv;
805 unsigned int u;
806
807 for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
808 data[u] = a5psw_read_stat(a5psw, a5psw_stats[u].offset, port);
809}
810
811static int a5psw_get_sset_count(struct dsa_switch *ds, int port, int sset)
812{
813 if (sset != ETH_SS_STATS)
814 return 0;
815
816 return ARRAY_SIZE(a5psw_stats);
817}
818
819static void a5psw_get_eth_mac_stats(struct dsa_switch *ds, int port,
820 struct ethtool_eth_mac_stats *mac_stats)
821{
822 struct a5psw *a5psw = ds->priv;
823
824#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
825 mac_stats->FramesTransmittedOK = RD(aFramesTransmittedOK);
826 mac_stats->SingleCollisionFrames = RD(aSingleCollisions);
827 mac_stats->MultipleCollisionFrames = RD(aMultipleCollisions);
828 mac_stats->FramesReceivedOK = RD(aFramesReceivedOK);
829 mac_stats->FrameCheckSequenceErrors = RD(aFrameCheckSequenceErrors);
830 mac_stats->AlignmentErrors = RD(aAlignmentErrors);
831 mac_stats->OctetsTransmittedOK = RD(aOctetsTransmittedOK);
832 mac_stats->FramesWithDeferredXmissions = RD(aDeferred);
833 mac_stats->LateCollisions = RD(aLateCollisions);
834 mac_stats->FramesAbortedDueToXSColls = RD(aExcessiveCollisions);
835 mac_stats->FramesLostDueToIntMACXmitError = RD(ifOutErrors);
836 mac_stats->CarrierSenseErrors = RD(aCarrierSenseErrors);
837 mac_stats->OctetsReceivedOK = RD(aOctetsReceivedOK);
838 mac_stats->FramesLostDueToIntMACRcvError = RD(ifInErrors);
839 mac_stats->MulticastFramesXmittedOK = RD(ifOutMulticastPkts);
840 mac_stats->BroadcastFramesXmittedOK = RD(ifOutBroadcastPkts);
841 mac_stats->FramesWithExcessiveDeferral = RD(aDeferred);
842 mac_stats->MulticastFramesReceivedOK = RD(ifInMulticastPkts);
843 mac_stats->BroadcastFramesReceivedOK = RD(ifInBroadcastPkts);
844#undef RD
845}
846
847static const struct ethtool_rmon_hist_range a5psw_rmon_ranges[] = {
848 { 0, 64 },
849 { 65, 127 },
850 { 128, 255 },
851 { 256, 511 },
852 { 512, 1023 },
853 { 1024, 1518 },
854 { 1519, A5PSW_MAX_MTU },
855 {}
856};
857
858static void a5psw_get_rmon_stats(struct dsa_switch *ds, int port,
859 struct ethtool_rmon_stats *rmon_stats,
860 const struct ethtool_rmon_hist_range **ranges)
861{
862 struct a5psw *a5psw = ds->priv;
863
864#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
865 rmon_stats->undersize_pkts = RD(etherStatsUndersizePkts);
866 rmon_stats->oversize_pkts = RD(etherStatsOversizePkts);
867 rmon_stats->fragments = RD(etherStatsFragments);
868 rmon_stats->jabbers = RD(etherStatsJabbers);
869 rmon_stats->hist[0] = RD(etherStatsPkts64Octets);
870 rmon_stats->hist[1] = RD(etherStatsPkts65to127Octets);
871 rmon_stats->hist[2] = RD(etherStatsPkts128to255Octets);
872 rmon_stats->hist[3] = RD(etherStatsPkts256to511Octets);
873 rmon_stats->hist[4] = RD(etherStatsPkts512to1023Octets);
874 rmon_stats->hist[5] = RD(etherStatsPkts1024to1518Octets);
875 rmon_stats->hist[6] = RD(etherStatsPkts1519toXOctets);
876#undef RD
877
878 *ranges = a5psw_rmon_ranges;
879}
880
881static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
882 struct ethtool_eth_ctrl_stats *ctrl_stats)
883{
884 struct a5psw *a5psw = ds->priv;
885 u64 stat;
886
887 stat = a5psw_read_stat(a5psw, A5PSW_aTxPAUSEMACCtrlFrames, port);
888 ctrl_stats->MACControlFramesTransmitted = stat;
889 stat = a5psw_read_stat(a5psw, A5PSW_aRxPAUSEMACCtrlFrames, port);
890 ctrl_stats->MACControlFramesReceived = stat;
891}
892
893static void a5psw_vlan_setup(struct a5psw *a5psw, int port)
894{
895 u32 reg;
896
897 /* Enable TAG always mode for the port, this is actually controlled
898 * by VLAN_IN_MODE_ENA field which will be used for PVID insertion
899 */
900 reg = A5PSW_VLAN_IN_MODE_TAG_ALWAYS;
901 reg <<= A5PSW_VLAN_IN_MODE_PORT_SHIFT(port);
902 a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE, A5PSW_VLAN_IN_MODE_PORT(port),
903 reg);
904
905 /* Set transparent mode for output frame manipulation, this will depend
906 * on the VLAN_RES configuration mode
907 */
908 reg = A5PSW_VLAN_OUT_MODE_TRANSPARENT;
909 reg <<= A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port);
910 a5psw_reg_rmw(a5psw, A5PSW_VLAN_OUT_MODE,
911 A5PSW_VLAN_OUT_MODE_PORT(port), reg);
912}
913
914static int a5psw_setup(struct dsa_switch *ds)
915{
916 struct a5psw *a5psw = ds->priv;
917 int port, vlan, ret;
918 struct dsa_port *dp;
919 u32 reg;
920
921 /* Validate that there is only 1 CPU port with index A5PSW_CPU_PORT */
922 dsa_switch_for_each_cpu_port(dp, ds) {
923 if (dp->index != A5PSW_CPU_PORT) {
924 dev_err(a5psw->dev, "Invalid CPU port\n");
925 return -EINVAL;
926 }
927 }
928
929 /* Configure management port */
930 reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_ENABLE;
931 a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg);
932
933 /* Set pattern 0 to forward all frame to mgmt port */
934 a5psw_reg_writel(a5psw, A5PSW_PATTERN_CTRL(A5PSW_PATTERN_MGMTFWD),
935 A5PSW_PATTERN_CTRL_MGMTFWD);
936
937 /* Enable port tagging */
938 reg = FIELD_PREP(A5PSW_MGMT_TAG_CFG_TAGFIELD, ETH_P_DSA_A5PSW);
939 reg |= A5PSW_MGMT_TAG_CFG_ENABLE | A5PSW_MGMT_TAG_CFG_ALL_FRAMES;
940 a5psw_reg_writel(a5psw, A5PSW_MGMT_TAG_CFG, reg);
941
942 /* Enable normal switch operation */
943 reg = A5PSW_LK_ADDR_CTRL_BLOCKING | A5PSW_LK_ADDR_CTRL_LEARNING |
944 A5PSW_LK_ADDR_CTRL_AGEING | A5PSW_LK_ADDR_CTRL_ALLOW_MIGR |
945 A5PSW_LK_ADDR_CTRL_CLEAR_TABLE;
946 a5psw_reg_writel(a5psw, A5PSW_LK_CTRL, reg);
947
948 ret = readl_poll_timeout(a5psw->base + A5PSW_LK_CTRL, reg,
949 !(reg & A5PSW_LK_ADDR_CTRL_CLEAR_TABLE),
950 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
951 if (ret) {
952 dev_err(a5psw->dev, "Failed to clear lookup table\n");
953 return ret;
954 }
955
956 /* Reset learn count to 0 */
957 reg = A5PSW_LK_LEARNCOUNT_MODE_SET;
958 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
959
960 /* Clear VLAN resource table */
961 reg = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_WR_TAGMASK;
962 for (vlan = 0; vlan < A5PSW_VLAN_COUNT; vlan++)
963 a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(vlan), reg);
964
965 /* Reset all ports */
966 dsa_switch_for_each_port(dp, ds) {
967 port = dp->index;
968
969 /* Reset the port */
970 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port),
971 A5PSW_CMD_CFG_SW_RESET);
972
973 /* Enable only CPU port */
974 a5psw_port_enable_set(a5psw, port, dsa_port_is_cpu(dp));
975
976 if (dsa_port_is_unused(dp))
977 continue;
978
979 /* Enable egress flooding and learning for CPU port */
980 if (dsa_port_is_cpu(dp)) {
981 a5psw_flooding_set_resolution(a5psw, port, true);
982 a5psw_port_learning_set(a5psw, port, true);
983 }
984
985 /* Enable standalone mode for user ports */
986 if (dsa_port_is_user(dp))
987 a5psw_port_set_standalone(a5psw, port, true);
988
989 a5psw_vlan_setup(a5psw, port);
990 }
991
992 return 0;
993}
994
995static const struct dsa_switch_ops a5psw_switch_ops = {
996 .get_tag_protocol = a5psw_get_tag_protocol,
997 .setup = a5psw_setup,
998 .port_disable = a5psw_port_disable,
999 .port_enable = a5psw_port_enable,
1000 .phylink_get_caps = a5psw_phylink_get_caps,
1001 .phylink_mac_select_pcs = a5psw_phylink_mac_select_pcs,
1002 .phylink_mac_link_down = a5psw_phylink_mac_link_down,
1003 .phylink_mac_link_up = a5psw_phylink_mac_link_up,
1004 .port_change_mtu = a5psw_port_change_mtu,
1005 .port_max_mtu = a5psw_port_max_mtu,
1006 .get_sset_count = a5psw_get_sset_count,
1007 .get_strings = a5psw_get_strings,
1008 .get_ethtool_stats = a5psw_get_ethtool_stats,
1009 .get_eth_mac_stats = a5psw_get_eth_mac_stats,
1010 .get_eth_ctrl_stats = a5psw_get_eth_ctrl_stats,
1011 .get_rmon_stats = a5psw_get_rmon_stats,
1012 .set_ageing_time = a5psw_set_ageing_time,
1013 .port_bridge_join = a5psw_port_bridge_join,
1014 .port_bridge_leave = a5psw_port_bridge_leave,
1015 .port_pre_bridge_flags = a5psw_port_pre_bridge_flags,
1016 .port_bridge_flags = a5psw_port_bridge_flags,
1017 .port_stp_state_set = a5psw_port_stp_state_set,
1018 .port_fast_age = a5psw_port_fast_age,
1019 .port_vlan_filtering = a5psw_port_vlan_filtering,
1020 .port_vlan_add = a5psw_port_vlan_add,
1021 .port_vlan_del = a5psw_port_vlan_del,
1022 .port_fdb_add = a5psw_port_fdb_add,
1023 .port_fdb_del = a5psw_port_fdb_del,
1024 .port_fdb_dump = a5psw_port_fdb_dump,
1025};
1026
1027static int a5psw_mdio_wait_busy(struct a5psw *a5psw)
1028{
1029 u32 status;
1030 int err;
1031
1032 err = readl_poll_timeout(a5psw->base + A5PSW_MDIO_CFG_STATUS, status,
1033 !(status & A5PSW_MDIO_CFG_STATUS_BUSY), 10,
1034 1000 * USEC_PER_MSEC);
1035 if (err)
1036 dev_err(a5psw->dev, "MDIO command timeout\n");
1037
1038 return err;
1039}
1040
1041static int a5psw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
1042{
1043 struct a5psw *a5psw = bus->priv;
1044 u32 cmd, status;
1045 int ret;
1046
1047 cmd = A5PSW_MDIO_COMMAND_READ;
1048 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
1049 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
1050
1051 a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
1052
1053 ret = a5psw_mdio_wait_busy(a5psw);
1054 if (ret)
1055 return ret;
1056
1057 ret = a5psw_reg_readl(a5psw, A5PSW_MDIO_DATA) & A5PSW_MDIO_DATA_MASK;
1058
1059 status = a5psw_reg_readl(a5psw, A5PSW_MDIO_CFG_STATUS);
1060 if (status & A5PSW_MDIO_CFG_STATUS_READERR)
1061 return -EIO;
1062
1063 return ret;
1064}
1065
1066static int a5psw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
1067 u16 phy_data)
1068{
1069 struct a5psw *a5psw = bus->priv;
1070 u32 cmd;
1071
1072 cmd = FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
1073 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
1074
1075 a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
1076 a5psw_reg_writel(a5psw, A5PSW_MDIO_DATA, phy_data);
1077
1078 return a5psw_mdio_wait_busy(a5psw);
1079}
1080
1081static int a5psw_mdio_config(struct a5psw *a5psw, u32 mdio_freq)
1082{
1083 unsigned long rate;
1084 unsigned long div;
1085 u32 cfgstatus;
1086
1087 rate = clk_get_rate(a5psw->hclk);
1088 div = ((rate / mdio_freq) / 2);
1089 if (div > FIELD_MAX(A5PSW_MDIO_CFG_STATUS_CLKDIV) ||
1090 div < A5PSW_MDIO_CLK_DIV_MIN) {
1091 dev_err(a5psw->dev, "MDIO clock div %ld out of range\n", div);
1092 return -ERANGE;
1093 }
1094
1095 cfgstatus = FIELD_PREP(A5PSW_MDIO_CFG_STATUS_CLKDIV, div);
1096
1097 a5psw_reg_writel(a5psw, A5PSW_MDIO_CFG_STATUS, cfgstatus);
1098
1099 return 0;
1100}
1101
1102static int a5psw_probe_mdio(struct a5psw *a5psw, struct device_node *node)
1103{
1104 struct device *dev = a5psw->dev;
1105 struct mii_bus *bus;
1106 u32 mdio_freq;
1107 int ret;
1108
1109 if (of_property_read_u32(node, "clock-frequency", &mdio_freq))
1110 mdio_freq = A5PSW_MDIO_DEF_FREQ;
1111
1112 ret = a5psw_mdio_config(a5psw, mdio_freq);
1113 if (ret)
1114 return ret;
1115
1116 bus = devm_mdiobus_alloc(dev);
1117 if (!bus)
1118 return -ENOMEM;
1119
1120 bus->name = "a5psw_mdio";
1121 bus->read = a5psw_mdio_read;
1122 bus->write = a5psw_mdio_write;
1123 bus->priv = a5psw;
1124 bus->parent = dev;
1125 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
1126
1127 a5psw->mii_bus = bus;
1128
1129 return devm_of_mdiobus_register(dev, bus, node);
1130}
1131
1132static void a5psw_pcs_free(struct a5psw *a5psw)
1133{
1134 int i;
1135
1136 for (i = 0; i < ARRAY_SIZE(a5psw->pcs); i++) {
1137 if (a5psw->pcs[i])
1138 miic_destroy(a5psw->pcs[i]);
1139 }
1140}
1141
1142static int a5psw_pcs_get(struct a5psw *a5psw)
1143{
1144 struct device_node *ports, *port, *pcs_node;
1145 struct phylink_pcs *pcs;
1146 int ret;
1147 u32 reg;
1148
1149 ports = of_get_child_by_name(a5psw->dev->of_node, "ethernet-ports");
1150 if (!ports)
1151 return -EINVAL;
1152
1153 for_each_available_child_of_node(ports, port) {
1154 pcs_node = of_parse_phandle(port, "pcs-handle", 0);
1155 if (!pcs_node)
1156 continue;
1157
1158 if (of_property_read_u32(port, "reg", ®)) {
1159 ret = -EINVAL;
1160 goto free_pcs;
1161 }
1162
1163 if (reg >= ARRAY_SIZE(a5psw->pcs)) {
1164 ret = -ENODEV;
1165 goto free_pcs;
1166 }
1167
1168 pcs = miic_create(a5psw->dev, pcs_node);
1169 if (IS_ERR(pcs)) {
1170 dev_err(a5psw->dev, "Failed to create PCS for port %d\n",
1171 reg);
1172 ret = PTR_ERR(pcs);
1173 goto free_pcs;
1174 }
1175
1176 a5psw->pcs[reg] = pcs;
1177 of_node_put(pcs_node);
1178 }
1179 of_node_put(ports);
1180
1181 return 0;
1182
1183free_pcs:
1184 of_node_put(pcs_node);
1185 of_node_put(port);
1186 of_node_put(ports);
1187 a5psw_pcs_free(a5psw);
1188
1189 return ret;
1190}
1191
1192static int a5psw_probe(struct platform_device *pdev)
1193{
1194 struct device *dev = &pdev->dev;
1195 struct device_node *mdio;
1196 struct dsa_switch *ds;
1197 struct a5psw *a5psw;
1198 int ret;
1199
1200 a5psw = devm_kzalloc(dev, sizeof(*a5psw), GFP_KERNEL);
1201 if (!a5psw)
1202 return -ENOMEM;
1203
1204 a5psw->dev = dev;
1205 mutex_init(&a5psw->lk_lock);
1206 spin_lock_init(&a5psw->reg_lock);
1207 a5psw->base = devm_platform_ioremap_resource(pdev, 0);
1208 if (IS_ERR(a5psw->base))
1209 return PTR_ERR(a5psw->base);
1210
1211 a5psw->bridged_ports = BIT(A5PSW_CPU_PORT);
1212
1213 ret = a5psw_pcs_get(a5psw);
1214 if (ret)
1215 return ret;
1216
1217 a5psw->hclk = devm_clk_get(dev, "hclk");
1218 if (IS_ERR(a5psw->hclk)) {
1219 dev_err(dev, "failed get hclk clock\n");
1220 ret = PTR_ERR(a5psw->hclk);
1221 goto free_pcs;
1222 }
1223
1224 a5psw->clk = devm_clk_get(dev, "clk");
1225 if (IS_ERR(a5psw->clk)) {
1226 dev_err(dev, "failed get clk_switch clock\n");
1227 ret = PTR_ERR(a5psw->clk);
1228 goto free_pcs;
1229 }
1230
1231 ret = clk_prepare_enable(a5psw->clk);
1232 if (ret)
1233 goto free_pcs;
1234
1235 ret = clk_prepare_enable(a5psw->hclk);
1236 if (ret)
1237 goto clk_disable;
1238
1239 mdio = of_get_child_by_name(dev->of_node, "mdio");
1240 if (of_device_is_available(mdio)) {
1241 ret = a5psw_probe_mdio(a5psw, mdio);
1242 if (ret) {
1243 of_node_put(mdio);
1244 dev_err(dev, "Failed to register MDIO: %d\n", ret);
1245 goto hclk_disable;
1246 }
1247 }
1248
1249 of_node_put(mdio);
1250
1251 ds = &a5psw->ds;
1252 ds->dev = dev;
1253 ds->num_ports = A5PSW_PORTS_NUM;
1254 ds->ops = &a5psw_switch_ops;
1255 ds->priv = a5psw;
1256
1257 ret = dsa_register_switch(ds);
1258 if (ret) {
1259 dev_err(dev, "Failed to register DSA switch: %d\n", ret);
1260 goto hclk_disable;
1261 }
1262
1263 return 0;
1264
1265hclk_disable:
1266 clk_disable_unprepare(a5psw->hclk);
1267clk_disable:
1268 clk_disable_unprepare(a5psw->clk);
1269free_pcs:
1270 a5psw_pcs_free(a5psw);
1271
1272 return ret;
1273}
1274
1275static void a5psw_remove(struct platform_device *pdev)
1276{
1277 struct a5psw *a5psw = platform_get_drvdata(pdev);
1278
1279 if (!a5psw)
1280 return;
1281
1282 dsa_unregister_switch(&a5psw->ds);
1283 a5psw_pcs_free(a5psw);
1284 clk_disable_unprepare(a5psw->hclk);
1285 clk_disable_unprepare(a5psw->clk);
1286}
1287
1288static void a5psw_shutdown(struct platform_device *pdev)
1289{
1290 struct a5psw *a5psw = platform_get_drvdata(pdev);
1291
1292 if (!a5psw)
1293 return;
1294
1295 dsa_switch_shutdown(&a5psw->ds);
1296
1297 platform_set_drvdata(pdev, NULL);
1298}
1299
1300static const struct of_device_id a5psw_of_mtable[] = {
1301 { .compatible = "renesas,rzn1-a5psw", },
1302 { /* sentinel */ },
1303};
1304MODULE_DEVICE_TABLE(of, a5psw_of_mtable);
1305
1306static struct platform_driver a5psw_driver = {
1307 .driver = {
1308 .name = "rzn1_a5psw",
1309 .of_match_table = a5psw_of_mtable,
1310 },
1311 .probe = a5psw_probe,
1312 .remove_new = a5psw_remove,
1313 .shutdown = a5psw_shutdown,
1314};
1315module_platform_driver(a5psw_driver);
1316
1317MODULE_LICENSE("GPL");
1318MODULE_DESCRIPTION("Renesas RZ/N1 Advanced 5-port Switch driver");
1319MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2022 Schneider-Electric
4 *
5 * Clément Léger <clement.leger@bootlin.com>
6 */
7
8#include <linux/clk.h>
9#include <linux/etherdevice.h>
10#include <linux/if_bridge.h>
11#include <linux/if_ether.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_mdio.h>
16#include <net/dsa.h>
17
18#include "rzn1_a5psw.h"
19
20struct a5psw_stats {
21 u16 offset;
22 const char name[ETH_GSTRING_LEN];
23};
24
25#define STAT_DESC(_offset) { \
26 .offset = A5PSW_##_offset, \
27 .name = __stringify(_offset), \
28}
29
30static const struct a5psw_stats a5psw_stats[] = {
31 STAT_DESC(aFramesTransmittedOK),
32 STAT_DESC(aFramesReceivedOK),
33 STAT_DESC(aFrameCheckSequenceErrors),
34 STAT_DESC(aAlignmentErrors),
35 STAT_DESC(aOctetsTransmittedOK),
36 STAT_DESC(aOctetsReceivedOK),
37 STAT_DESC(aTxPAUSEMACCtrlFrames),
38 STAT_DESC(aRxPAUSEMACCtrlFrames),
39 STAT_DESC(ifInErrors),
40 STAT_DESC(ifOutErrors),
41 STAT_DESC(ifInUcastPkts),
42 STAT_DESC(ifInMulticastPkts),
43 STAT_DESC(ifInBroadcastPkts),
44 STAT_DESC(ifOutDiscards),
45 STAT_DESC(ifOutUcastPkts),
46 STAT_DESC(ifOutMulticastPkts),
47 STAT_DESC(ifOutBroadcastPkts),
48 STAT_DESC(etherStatsDropEvents),
49 STAT_DESC(etherStatsOctets),
50 STAT_DESC(etherStatsPkts),
51 STAT_DESC(etherStatsUndersizePkts),
52 STAT_DESC(etherStatsOversizePkts),
53 STAT_DESC(etherStatsPkts64Octets),
54 STAT_DESC(etherStatsPkts65to127Octets),
55 STAT_DESC(etherStatsPkts128to255Octets),
56 STAT_DESC(etherStatsPkts256to511Octets),
57 STAT_DESC(etherStatsPkts1024to1518Octets),
58 STAT_DESC(etherStatsPkts1519toXOctets),
59 STAT_DESC(etherStatsJabbers),
60 STAT_DESC(etherStatsFragments),
61 STAT_DESC(VLANReceived),
62 STAT_DESC(VLANTransmitted),
63 STAT_DESC(aDeferred),
64 STAT_DESC(aMultipleCollisions),
65 STAT_DESC(aSingleCollisions),
66 STAT_DESC(aLateCollisions),
67 STAT_DESC(aExcessiveCollisions),
68 STAT_DESC(aCarrierSenseErrors),
69};
70
71static void a5psw_reg_writel(struct a5psw *a5psw, int offset, u32 value)
72{
73 writel(value, a5psw->base + offset);
74}
75
76static u32 a5psw_reg_readl(struct a5psw *a5psw, int offset)
77{
78 return readl(a5psw->base + offset);
79}
80
81static void a5psw_reg_rmw(struct a5psw *a5psw, int offset, u32 mask, u32 val)
82{
83 u32 reg;
84
85 spin_lock(&a5psw->reg_lock);
86
87 reg = a5psw_reg_readl(a5psw, offset);
88 reg &= ~mask;
89 reg |= val;
90 a5psw_reg_writel(a5psw, offset, reg);
91
92 spin_unlock(&a5psw->reg_lock);
93}
94
95static enum dsa_tag_protocol a5psw_get_tag_protocol(struct dsa_switch *ds,
96 int port,
97 enum dsa_tag_protocol mp)
98{
99 return DSA_TAG_PROTO_RZN1_A5PSW;
100}
101
102static void a5psw_port_pattern_set(struct a5psw *a5psw, int port, int pattern,
103 bool enable)
104{
105 u32 rx_match = 0;
106
107 if (enable)
108 rx_match |= A5PSW_RXMATCH_CONFIG_PATTERN(pattern);
109
110 a5psw_reg_rmw(a5psw, A5PSW_RXMATCH_CONFIG(port),
111 A5PSW_RXMATCH_CONFIG_PATTERN(pattern), rx_match);
112}
113
114static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable)
115{
116 /* Enable "management forward" pattern matching, this will forward
117 * packets from this port only towards the management port and thus
118 * isolate the port.
119 */
120 a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable);
121}
122
123static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable)
124{
125 u32 port_ena = 0;
126
127 if (enable)
128 port_ena |= A5PSW_PORT_ENA_TX_RX(port);
129
130 a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, A5PSW_PORT_ENA_TX_RX(port),
131 port_ena);
132}
133
134static int a5psw_lk_execute_ctrl(struct a5psw *a5psw, u32 *ctrl)
135{
136 int ret;
137
138 a5psw_reg_writel(a5psw, A5PSW_LK_ADDR_CTRL, *ctrl);
139
140 ret = readl_poll_timeout(a5psw->base + A5PSW_LK_ADDR_CTRL, *ctrl,
141 !(*ctrl & A5PSW_LK_ADDR_CTRL_BUSY),
142 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
143 if (ret)
144 dev_err(a5psw->dev, "LK_CTRL timeout waiting for BUSY bit\n");
145
146 return ret;
147}
148
149static void a5psw_port_fdb_flush(struct a5psw *a5psw, int port)
150{
151 u32 ctrl = A5PSW_LK_ADDR_CTRL_DELETE_PORT | BIT(port);
152
153 mutex_lock(&a5psw->lk_lock);
154 a5psw_lk_execute_ctrl(a5psw, &ctrl);
155 mutex_unlock(&a5psw->lk_lock);
156}
157
158static void a5psw_port_authorize_set(struct a5psw *a5psw, int port,
159 bool authorize)
160{
161 u32 reg = a5psw_reg_readl(a5psw, A5PSW_AUTH_PORT(port));
162
163 if (authorize)
164 reg |= A5PSW_AUTH_PORT_AUTHORIZED;
165 else
166 reg &= ~A5PSW_AUTH_PORT_AUTHORIZED;
167
168 a5psw_reg_writel(a5psw, A5PSW_AUTH_PORT(port), reg);
169}
170
171static void a5psw_port_disable(struct dsa_switch *ds, int port)
172{
173 struct a5psw *a5psw = ds->priv;
174
175 a5psw_port_authorize_set(a5psw, port, false);
176 a5psw_port_enable_set(a5psw, port, false);
177}
178
179static int a5psw_port_enable(struct dsa_switch *ds, int port,
180 struct phy_device *phy)
181{
182 struct a5psw *a5psw = ds->priv;
183
184 a5psw_port_authorize_set(a5psw, port, true);
185 a5psw_port_enable_set(a5psw, port, true);
186
187 return 0;
188}
189
190static int a5psw_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
191{
192 struct a5psw *a5psw = ds->priv;
193
194 new_mtu += ETH_HLEN + A5PSW_EXTRA_MTU_LEN + ETH_FCS_LEN;
195 a5psw_reg_writel(a5psw, A5PSW_FRM_LENGTH(port), new_mtu);
196
197 return 0;
198}
199
200static int a5psw_port_max_mtu(struct dsa_switch *ds, int port)
201{
202 return A5PSW_MAX_MTU;
203}
204
205static void a5psw_phylink_get_caps(struct dsa_switch *ds, int port,
206 struct phylink_config *config)
207{
208 unsigned long *intf = config->supported_interfaces;
209
210 config->mac_capabilities = MAC_1000FD;
211
212 if (dsa_is_cpu_port(ds, port)) {
213 /* GMII is used internally and GMAC2 is connected to the switch
214 * using 1000Mbps Full-Duplex mode only (cf ethernet manual)
215 */
216 __set_bit(PHY_INTERFACE_MODE_GMII, intf);
217 } else {
218 config->mac_capabilities |= MAC_100 | MAC_10;
219 phy_interface_set_rgmii(intf);
220 __set_bit(PHY_INTERFACE_MODE_RMII, intf);
221 __set_bit(PHY_INTERFACE_MODE_MII, intf);
222 }
223}
224
225static struct phylink_pcs *
226a5psw_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
227 phy_interface_t interface)
228{
229 struct dsa_port *dp = dsa_to_port(ds, port);
230 struct a5psw *a5psw = ds->priv;
231
232 if (!dsa_port_is_cpu(dp) && a5psw->pcs[port])
233 return a5psw->pcs[port];
234
235 return NULL;
236}
237
238static void a5psw_phylink_mac_link_down(struct dsa_switch *ds, int port,
239 unsigned int mode,
240 phy_interface_t interface)
241{
242 struct a5psw *a5psw = ds->priv;
243 u32 cmd_cfg;
244
245 cmd_cfg = a5psw_reg_readl(a5psw, A5PSW_CMD_CFG(port));
246 cmd_cfg &= ~(A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA);
247 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
248}
249
250static void a5psw_phylink_mac_link_up(struct dsa_switch *ds, int port,
251 unsigned int mode,
252 phy_interface_t interface,
253 struct phy_device *phydev, int speed,
254 int duplex, bool tx_pause, bool rx_pause)
255{
256 u32 cmd_cfg = A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA |
257 A5PSW_CMD_CFG_TX_CRC_APPEND;
258 struct a5psw *a5psw = ds->priv;
259
260 if (speed == SPEED_1000)
261 cmd_cfg |= A5PSW_CMD_CFG_ETH_SPEED;
262
263 if (duplex == DUPLEX_HALF)
264 cmd_cfg |= A5PSW_CMD_CFG_HD_ENA;
265
266 cmd_cfg |= A5PSW_CMD_CFG_CNTL_FRM_ENA;
267
268 if (!rx_pause)
269 cmd_cfg &= ~A5PSW_CMD_CFG_PAUSE_IGNORE;
270
271 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
272}
273
274static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
275{
276 struct a5psw *a5psw = ds->priv;
277 unsigned long rate;
278 u64 max, tmp;
279 u32 agetime;
280
281 rate = clk_get_rate(a5psw->clk);
282 max = div64_ul(((u64)A5PSW_LK_AGETIME_MASK * A5PSW_TABLE_ENTRIES * 1024),
283 rate) * 1000;
284 if (msecs > max)
285 return -EINVAL;
286
287 tmp = div_u64(rate, MSEC_PER_SEC);
288 agetime = div_u64(msecs * tmp, 1024 * A5PSW_TABLE_ENTRIES);
289
290 a5psw_reg_writel(a5psw, A5PSW_LK_AGETIME, agetime);
291
292 return 0;
293}
294
295static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
296 bool set)
297{
298 u8 offsets[] = {A5PSW_UCAST_DEF_MASK, A5PSW_BCAST_DEF_MASK,
299 A5PSW_MCAST_DEF_MASK};
300 int i;
301
302 if (set)
303 a5psw->bridged_ports |= BIT(port);
304 else
305 a5psw->bridged_ports &= ~BIT(port);
306
307 for (i = 0; i < ARRAY_SIZE(offsets); i++)
308 a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports);
309}
310
311static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
312 struct dsa_bridge bridge,
313 bool *tx_fwd_offload,
314 struct netlink_ext_ack *extack)
315{
316 struct a5psw *a5psw = ds->priv;
317
318 /* We only support 1 bridge device */
319 if (a5psw->br_dev && bridge.dev != a5psw->br_dev) {
320 NL_SET_ERR_MSG_MOD(extack,
321 "Forwarding offload supported for a single bridge");
322 return -EOPNOTSUPP;
323 }
324
325 a5psw->br_dev = bridge.dev;
326 a5psw_flooding_set_resolution(a5psw, port, true);
327 a5psw_port_mgmtfwd_set(a5psw, port, false);
328
329 return 0;
330}
331
332static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
333 struct dsa_bridge bridge)
334{
335 struct a5psw *a5psw = ds->priv;
336
337 a5psw_flooding_set_resolution(a5psw, port, false);
338 a5psw_port_mgmtfwd_set(a5psw, port, true);
339
340 /* No more ports bridged */
341 if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT))
342 a5psw->br_dev = NULL;
343}
344
345static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
346{
347 u32 mask = A5PSW_INPUT_LEARN_DIS(port) | A5PSW_INPUT_LEARN_BLOCK(port);
348 struct a5psw *a5psw = ds->priv;
349 u32 reg = 0;
350
351 switch (state) {
352 case BR_STATE_DISABLED:
353 case BR_STATE_BLOCKING:
354 reg |= A5PSW_INPUT_LEARN_DIS(port);
355 reg |= A5PSW_INPUT_LEARN_BLOCK(port);
356 break;
357 case BR_STATE_LISTENING:
358 reg |= A5PSW_INPUT_LEARN_DIS(port);
359 break;
360 case BR_STATE_LEARNING:
361 reg |= A5PSW_INPUT_LEARN_BLOCK(port);
362 break;
363 case BR_STATE_FORWARDING:
364 default:
365 break;
366 }
367
368 a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
369}
370
371static void a5psw_port_fast_age(struct dsa_switch *ds, int port)
372{
373 struct a5psw *a5psw = ds->priv;
374
375 a5psw_port_fdb_flush(a5psw, port);
376}
377
378static int a5psw_lk_execute_lookup(struct a5psw *a5psw, union lk_data *lk_data,
379 u16 *entry)
380{
381 u32 ctrl;
382 int ret;
383
384 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_LO, lk_data->lo);
385 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data->hi);
386
387 ctrl = A5PSW_LK_ADDR_CTRL_LOOKUP;
388 ret = a5psw_lk_execute_ctrl(a5psw, &ctrl);
389 if (ret)
390 return ret;
391
392 *entry = ctrl & A5PSW_LK_ADDR_CTRL_ADDRESS;
393
394 return 0;
395}
396
397static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
398 const unsigned char *addr, u16 vid,
399 struct dsa_db db)
400{
401 struct a5psw *a5psw = ds->priv;
402 union lk_data lk_data = {0};
403 bool inc_learncount = false;
404 int ret = 0;
405 u16 entry;
406 u32 reg;
407
408 ether_addr_copy(lk_data.entry.mac, addr);
409 lk_data.entry.port_mask = BIT(port);
410
411 mutex_lock(&a5psw->lk_lock);
412
413 /* Set the value to be written in the lookup table */
414 ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
415 if (ret)
416 goto lk_unlock;
417
418 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
419 if (!lk_data.entry.valid) {
420 inc_learncount = true;
421 /* port_mask set to 0x1f when entry is not valid, clear it */
422 lk_data.entry.port_mask = 0;
423 lk_data.entry.prio = 0;
424 }
425
426 lk_data.entry.port_mask |= BIT(port);
427 lk_data.entry.is_static = 1;
428 lk_data.entry.valid = 1;
429
430 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
431
432 reg = A5PSW_LK_ADDR_CTRL_WRITE | entry;
433 ret = a5psw_lk_execute_ctrl(a5psw, ®);
434 if (ret)
435 goto lk_unlock;
436
437 if (inc_learncount) {
438 reg = A5PSW_LK_LEARNCOUNT_MODE_INC;
439 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
440 }
441
442lk_unlock:
443 mutex_unlock(&a5psw->lk_lock);
444
445 return ret;
446}
447
448static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
449 const unsigned char *addr, u16 vid,
450 struct dsa_db db)
451{
452 struct a5psw *a5psw = ds->priv;
453 union lk_data lk_data = {0};
454 bool clear = false;
455 u16 entry;
456 u32 reg;
457 int ret;
458
459 ether_addr_copy(lk_data.entry.mac, addr);
460
461 mutex_lock(&a5psw->lk_lock);
462
463 ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
464 if (ret)
465 goto lk_unlock;
466
467 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
468
469 /* Our hardware does not associate any VID to the FDB entries so this
470 * means that if two entries were added for the same mac but for
471 * different VID, then, on the deletion of the first one, we would also
472 * delete the second one. Since there is unfortunately nothing we can do
473 * about that, do not return an error...
474 */
475 if (!lk_data.entry.valid)
476 goto lk_unlock;
477
478 lk_data.entry.port_mask &= ~BIT(port);
479 /* If there is no more port in the mask, clear the entry */
480 if (lk_data.entry.port_mask == 0)
481 clear = true;
482
483 a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
484
485 reg = entry;
486 if (clear)
487 reg |= A5PSW_LK_ADDR_CTRL_CLEAR;
488 else
489 reg |= A5PSW_LK_ADDR_CTRL_WRITE;
490
491 ret = a5psw_lk_execute_ctrl(a5psw, ®);
492 if (ret)
493 goto lk_unlock;
494
495 /* Decrement LEARNCOUNT */
496 if (clear) {
497 reg = A5PSW_LK_LEARNCOUNT_MODE_DEC;
498 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
499 }
500
501lk_unlock:
502 mutex_unlock(&a5psw->lk_lock);
503
504 return ret;
505}
506
507static int a5psw_port_fdb_dump(struct dsa_switch *ds, int port,
508 dsa_fdb_dump_cb_t *cb, void *data)
509{
510 struct a5psw *a5psw = ds->priv;
511 union lk_data lk_data;
512 int i = 0, ret = 0;
513 u32 reg;
514
515 mutex_lock(&a5psw->lk_lock);
516
517 for (i = 0; i < A5PSW_TABLE_ENTRIES; i++) {
518 reg = A5PSW_LK_ADDR_CTRL_READ | A5PSW_LK_ADDR_CTRL_WAIT | i;
519
520 ret = a5psw_lk_execute_ctrl(a5psw, ®);
521 if (ret)
522 goto out_unlock;
523
524 lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
525 /* If entry is not valid or does not contain the port, skip */
526 if (!lk_data.entry.valid ||
527 !(lk_data.entry.port_mask & BIT(port)))
528 continue;
529
530 lk_data.lo = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_LO);
531
532 ret = cb(lk_data.entry.mac, 0, lk_data.entry.is_static, data);
533 if (ret)
534 goto out_unlock;
535 }
536
537out_unlock:
538 mutex_unlock(&a5psw->lk_lock);
539
540 return ret;
541}
542
543static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port)
544{
545 u32 reg_lo, reg_hi;
546
547 reg_lo = a5psw_reg_readl(a5psw, offset + A5PSW_PORT_OFFSET(port));
548 /* A5PSW_STATS_HIWORD is latched on stat read */
549 reg_hi = a5psw_reg_readl(a5psw, A5PSW_STATS_HIWORD);
550
551 return ((u64)reg_hi << 32) | reg_lo;
552}
553
554static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset,
555 uint8_t *data)
556{
557 unsigned int u;
558
559 if (stringset != ETH_SS_STATS)
560 return;
561
562 for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) {
563 memcpy(data + u * ETH_GSTRING_LEN, a5psw_stats[u].name,
564 ETH_GSTRING_LEN);
565 }
566}
567
568static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port,
569 uint64_t *data)
570{
571 struct a5psw *a5psw = ds->priv;
572 unsigned int u;
573
574 for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
575 data[u] = a5psw_read_stat(a5psw, a5psw_stats[u].offset, port);
576}
577
578static int a5psw_get_sset_count(struct dsa_switch *ds, int port, int sset)
579{
580 if (sset != ETH_SS_STATS)
581 return 0;
582
583 return ARRAY_SIZE(a5psw_stats);
584}
585
586static void a5psw_get_eth_mac_stats(struct dsa_switch *ds, int port,
587 struct ethtool_eth_mac_stats *mac_stats)
588{
589 struct a5psw *a5psw = ds->priv;
590
591#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
592 mac_stats->FramesTransmittedOK = RD(aFramesTransmittedOK);
593 mac_stats->SingleCollisionFrames = RD(aSingleCollisions);
594 mac_stats->MultipleCollisionFrames = RD(aMultipleCollisions);
595 mac_stats->FramesReceivedOK = RD(aFramesReceivedOK);
596 mac_stats->FrameCheckSequenceErrors = RD(aFrameCheckSequenceErrors);
597 mac_stats->AlignmentErrors = RD(aAlignmentErrors);
598 mac_stats->OctetsTransmittedOK = RD(aOctetsTransmittedOK);
599 mac_stats->FramesWithDeferredXmissions = RD(aDeferred);
600 mac_stats->LateCollisions = RD(aLateCollisions);
601 mac_stats->FramesAbortedDueToXSColls = RD(aExcessiveCollisions);
602 mac_stats->FramesLostDueToIntMACXmitError = RD(ifOutErrors);
603 mac_stats->CarrierSenseErrors = RD(aCarrierSenseErrors);
604 mac_stats->OctetsReceivedOK = RD(aOctetsReceivedOK);
605 mac_stats->FramesLostDueToIntMACRcvError = RD(ifInErrors);
606 mac_stats->MulticastFramesXmittedOK = RD(ifOutMulticastPkts);
607 mac_stats->BroadcastFramesXmittedOK = RD(ifOutBroadcastPkts);
608 mac_stats->FramesWithExcessiveDeferral = RD(aDeferred);
609 mac_stats->MulticastFramesReceivedOK = RD(ifInMulticastPkts);
610 mac_stats->BroadcastFramesReceivedOK = RD(ifInBroadcastPkts);
611#undef RD
612}
613
614static const struct ethtool_rmon_hist_range a5psw_rmon_ranges[] = {
615 { 0, 64 },
616 { 65, 127 },
617 { 128, 255 },
618 { 256, 511 },
619 { 512, 1023 },
620 { 1024, 1518 },
621 { 1519, A5PSW_MAX_MTU },
622 {}
623};
624
625static void a5psw_get_rmon_stats(struct dsa_switch *ds, int port,
626 struct ethtool_rmon_stats *rmon_stats,
627 const struct ethtool_rmon_hist_range **ranges)
628{
629 struct a5psw *a5psw = ds->priv;
630
631#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
632 rmon_stats->undersize_pkts = RD(etherStatsUndersizePkts);
633 rmon_stats->oversize_pkts = RD(etherStatsOversizePkts);
634 rmon_stats->fragments = RD(etherStatsFragments);
635 rmon_stats->jabbers = RD(etherStatsJabbers);
636 rmon_stats->hist[0] = RD(etherStatsPkts64Octets);
637 rmon_stats->hist[1] = RD(etherStatsPkts65to127Octets);
638 rmon_stats->hist[2] = RD(etherStatsPkts128to255Octets);
639 rmon_stats->hist[3] = RD(etherStatsPkts256to511Octets);
640 rmon_stats->hist[4] = RD(etherStatsPkts512to1023Octets);
641 rmon_stats->hist[5] = RD(etherStatsPkts1024to1518Octets);
642 rmon_stats->hist[6] = RD(etherStatsPkts1519toXOctets);
643#undef RD
644
645 *ranges = a5psw_rmon_ranges;
646}
647
648static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
649 struct ethtool_eth_ctrl_stats *ctrl_stats)
650{
651 struct a5psw *a5psw = ds->priv;
652 u64 stat;
653
654 stat = a5psw_read_stat(a5psw, A5PSW_aTxPAUSEMACCtrlFrames, port);
655 ctrl_stats->MACControlFramesTransmitted = stat;
656 stat = a5psw_read_stat(a5psw, A5PSW_aRxPAUSEMACCtrlFrames, port);
657 ctrl_stats->MACControlFramesReceived = stat;
658}
659
660static int a5psw_setup(struct dsa_switch *ds)
661{
662 struct a5psw *a5psw = ds->priv;
663 int port, vlan, ret;
664 struct dsa_port *dp;
665 u32 reg;
666
667 /* Validate that there is only 1 CPU port with index A5PSW_CPU_PORT */
668 dsa_switch_for_each_cpu_port(dp, ds) {
669 if (dp->index != A5PSW_CPU_PORT) {
670 dev_err(a5psw->dev, "Invalid CPU port\n");
671 return -EINVAL;
672 }
673 }
674
675 /* Configure management port */
676 reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_DISCARD;
677 a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg);
678
679 /* Set pattern 0 to forward all frame to mgmt port */
680 a5psw_reg_writel(a5psw, A5PSW_PATTERN_CTRL(A5PSW_PATTERN_MGMTFWD),
681 A5PSW_PATTERN_CTRL_MGMTFWD);
682
683 /* Enable port tagging */
684 reg = FIELD_PREP(A5PSW_MGMT_TAG_CFG_TAGFIELD, ETH_P_DSA_A5PSW);
685 reg |= A5PSW_MGMT_TAG_CFG_ENABLE | A5PSW_MGMT_TAG_CFG_ALL_FRAMES;
686 a5psw_reg_writel(a5psw, A5PSW_MGMT_TAG_CFG, reg);
687
688 /* Enable normal switch operation */
689 reg = A5PSW_LK_ADDR_CTRL_BLOCKING | A5PSW_LK_ADDR_CTRL_LEARNING |
690 A5PSW_LK_ADDR_CTRL_AGEING | A5PSW_LK_ADDR_CTRL_ALLOW_MIGR |
691 A5PSW_LK_ADDR_CTRL_CLEAR_TABLE;
692 a5psw_reg_writel(a5psw, A5PSW_LK_CTRL, reg);
693
694 ret = readl_poll_timeout(a5psw->base + A5PSW_LK_CTRL, reg,
695 !(reg & A5PSW_LK_ADDR_CTRL_CLEAR_TABLE),
696 A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
697 if (ret) {
698 dev_err(a5psw->dev, "Failed to clear lookup table\n");
699 return ret;
700 }
701
702 /* Reset learn count to 0 */
703 reg = A5PSW_LK_LEARNCOUNT_MODE_SET;
704 a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
705
706 /* Clear VLAN resource table */
707 reg = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_WR_TAGMASK;
708 for (vlan = 0; vlan < A5PSW_VLAN_COUNT; vlan++)
709 a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(vlan), reg);
710
711 /* Reset all ports */
712 dsa_switch_for_each_port(dp, ds) {
713 port = dp->index;
714
715 /* Reset the port */
716 a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port),
717 A5PSW_CMD_CFG_SW_RESET);
718
719 /* Enable only CPU port */
720 a5psw_port_enable_set(a5psw, port, dsa_port_is_cpu(dp));
721
722 if (dsa_port_is_unused(dp))
723 continue;
724
725 /* Enable egress flooding for CPU port */
726 if (dsa_port_is_cpu(dp))
727 a5psw_flooding_set_resolution(a5psw, port, true);
728
729 /* Enable management forward only for user ports */
730 if (dsa_port_is_user(dp))
731 a5psw_port_mgmtfwd_set(a5psw, port, true);
732 }
733
734 return 0;
735}
736
737static const struct dsa_switch_ops a5psw_switch_ops = {
738 .get_tag_protocol = a5psw_get_tag_protocol,
739 .setup = a5psw_setup,
740 .port_disable = a5psw_port_disable,
741 .port_enable = a5psw_port_enable,
742 .phylink_get_caps = a5psw_phylink_get_caps,
743 .phylink_mac_select_pcs = a5psw_phylink_mac_select_pcs,
744 .phylink_mac_link_down = a5psw_phylink_mac_link_down,
745 .phylink_mac_link_up = a5psw_phylink_mac_link_up,
746 .port_change_mtu = a5psw_port_change_mtu,
747 .port_max_mtu = a5psw_port_max_mtu,
748 .get_sset_count = a5psw_get_sset_count,
749 .get_strings = a5psw_get_strings,
750 .get_ethtool_stats = a5psw_get_ethtool_stats,
751 .get_eth_mac_stats = a5psw_get_eth_mac_stats,
752 .get_eth_ctrl_stats = a5psw_get_eth_ctrl_stats,
753 .get_rmon_stats = a5psw_get_rmon_stats,
754 .set_ageing_time = a5psw_set_ageing_time,
755 .port_bridge_join = a5psw_port_bridge_join,
756 .port_bridge_leave = a5psw_port_bridge_leave,
757 .port_stp_state_set = a5psw_port_stp_state_set,
758 .port_fast_age = a5psw_port_fast_age,
759 .port_fdb_add = a5psw_port_fdb_add,
760 .port_fdb_del = a5psw_port_fdb_del,
761 .port_fdb_dump = a5psw_port_fdb_dump,
762};
763
764static int a5psw_mdio_wait_busy(struct a5psw *a5psw)
765{
766 u32 status;
767 int err;
768
769 err = readl_poll_timeout(a5psw->base + A5PSW_MDIO_CFG_STATUS, status,
770 !(status & A5PSW_MDIO_CFG_STATUS_BUSY), 10,
771 1000 * USEC_PER_MSEC);
772 if (err)
773 dev_err(a5psw->dev, "MDIO command timeout\n");
774
775 return err;
776}
777
778static int a5psw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
779{
780 struct a5psw *a5psw = bus->priv;
781 u32 cmd, status;
782 int ret;
783
784 if (phy_reg & MII_ADDR_C45)
785 return -EOPNOTSUPP;
786
787 cmd = A5PSW_MDIO_COMMAND_READ;
788 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
789 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
790
791 a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
792
793 ret = a5psw_mdio_wait_busy(a5psw);
794 if (ret)
795 return ret;
796
797 ret = a5psw_reg_readl(a5psw, A5PSW_MDIO_DATA) & A5PSW_MDIO_DATA_MASK;
798
799 status = a5psw_reg_readl(a5psw, A5PSW_MDIO_CFG_STATUS);
800 if (status & A5PSW_MDIO_CFG_STATUS_READERR)
801 return -EIO;
802
803 return ret;
804}
805
806static int a5psw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
807 u16 phy_data)
808{
809 struct a5psw *a5psw = bus->priv;
810 u32 cmd;
811
812 if (phy_reg & MII_ADDR_C45)
813 return -EOPNOTSUPP;
814
815 cmd = FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
816 cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
817
818 a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
819 a5psw_reg_writel(a5psw, A5PSW_MDIO_DATA, phy_data);
820
821 return a5psw_mdio_wait_busy(a5psw);
822}
823
824static int a5psw_mdio_config(struct a5psw *a5psw, u32 mdio_freq)
825{
826 unsigned long rate;
827 unsigned long div;
828 u32 cfgstatus;
829
830 rate = clk_get_rate(a5psw->hclk);
831 div = ((rate / mdio_freq) / 2);
832 if (div > FIELD_MAX(A5PSW_MDIO_CFG_STATUS_CLKDIV) ||
833 div < A5PSW_MDIO_CLK_DIV_MIN) {
834 dev_err(a5psw->dev, "MDIO clock div %ld out of range\n", div);
835 return -ERANGE;
836 }
837
838 cfgstatus = FIELD_PREP(A5PSW_MDIO_CFG_STATUS_CLKDIV, div);
839
840 a5psw_reg_writel(a5psw, A5PSW_MDIO_CFG_STATUS, cfgstatus);
841
842 return 0;
843}
844
845static int a5psw_probe_mdio(struct a5psw *a5psw, struct device_node *node)
846{
847 struct device *dev = a5psw->dev;
848 struct mii_bus *bus;
849 u32 mdio_freq;
850 int ret;
851
852 if (of_property_read_u32(node, "clock-frequency", &mdio_freq))
853 mdio_freq = A5PSW_MDIO_DEF_FREQ;
854
855 ret = a5psw_mdio_config(a5psw, mdio_freq);
856 if (ret)
857 return ret;
858
859 bus = devm_mdiobus_alloc(dev);
860 if (!bus)
861 return -ENOMEM;
862
863 bus->name = "a5psw_mdio";
864 bus->read = a5psw_mdio_read;
865 bus->write = a5psw_mdio_write;
866 bus->priv = a5psw;
867 bus->parent = dev;
868 snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
869
870 a5psw->mii_bus = bus;
871
872 return devm_of_mdiobus_register(dev, bus, node);
873}
874
875static void a5psw_pcs_free(struct a5psw *a5psw)
876{
877 int i;
878
879 for (i = 0; i < ARRAY_SIZE(a5psw->pcs); i++) {
880 if (a5psw->pcs[i])
881 miic_destroy(a5psw->pcs[i]);
882 }
883}
884
885static int a5psw_pcs_get(struct a5psw *a5psw)
886{
887 struct device_node *ports, *port, *pcs_node;
888 struct phylink_pcs *pcs;
889 int ret;
890 u32 reg;
891
892 ports = of_get_child_by_name(a5psw->dev->of_node, "ethernet-ports");
893 if (!ports)
894 return -EINVAL;
895
896 for_each_available_child_of_node(ports, port) {
897 pcs_node = of_parse_phandle(port, "pcs-handle", 0);
898 if (!pcs_node)
899 continue;
900
901 if (of_property_read_u32(port, "reg", ®)) {
902 ret = -EINVAL;
903 goto free_pcs;
904 }
905
906 if (reg >= ARRAY_SIZE(a5psw->pcs)) {
907 ret = -ENODEV;
908 goto free_pcs;
909 }
910
911 pcs = miic_create(a5psw->dev, pcs_node);
912 if (IS_ERR(pcs)) {
913 dev_err(a5psw->dev, "Failed to create PCS for port %d\n",
914 reg);
915 ret = PTR_ERR(pcs);
916 goto free_pcs;
917 }
918
919 a5psw->pcs[reg] = pcs;
920 of_node_put(pcs_node);
921 }
922 of_node_put(ports);
923
924 return 0;
925
926free_pcs:
927 of_node_put(pcs_node);
928 of_node_put(port);
929 of_node_put(ports);
930 a5psw_pcs_free(a5psw);
931
932 return ret;
933}
934
935static int a5psw_probe(struct platform_device *pdev)
936{
937 struct device *dev = &pdev->dev;
938 struct device_node *mdio;
939 struct dsa_switch *ds;
940 struct a5psw *a5psw;
941 int ret;
942
943 a5psw = devm_kzalloc(dev, sizeof(*a5psw), GFP_KERNEL);
944 if (!a5psw)
945 return -ENOMEM;
946
947 a5psw->dev = dev;
948 mutex_init(&a5psw->lk_lock);
949 spin_lock_init(&a5psw->reg_lock);
950 a5psw->base = devm_platform_ioremap_resource(pdev, 0);
951 if (IS_ERR(a5psw->base))
952 return PTR_ERR(a5psw->base);
953
954 ret = a5psw_pcs_get(a5psw);
955 if (ret)
956 return ret;
957
958 a5psw->hclk = devm_clk_get(dev, "hclk");
959 if (IS_ERR(a5psw->hclk)) {
960 dev_err(dev, "failed get hclk clock\n");
961 ret = PTR_ERR(a5psw->hclk);
962 goto free_pcs;
963 }
964
965 a5psw->clk = devm_clk_get(dev, "clk");
966 if (IS_ERR(a5psw->clk)) {
967 dev_err(dev, "failed get clk_switch clock\n");
968 ret = PTR_ERR(a5psw->clk);
969 goto free_pcs;
970 }
971
972 ret = clk_prepare_enable(a5psw->clk);
973 if (ret)
974 goto free_pcs;
975
976 ret = clk_prepare_enable(a5psw->hclk);
977 if (ret)
978 goto clk_disable;
979
980 mdio = of_get_child_by_name(dev->of_node, "mdio");
981 if (of_device_is_available(mdio)) {
982 ret = a5psw_probe_mdio(a5psw, mdio);
983 if (ret) {
984 of_node_put(mdio);
985 dev_err(dev, "Failed to register MDIO: %d\n", ret);
986 goto hclk_disable;
987 }
988 }
989
990 of_node_put(mdio);
991
992 ds = &a5psw->ds;
993 ds->dev = dev;
994 ds->num_ports = A5PSW_PORTS_NUM;
995 ds->ops = &a5psw_switch_ops;
996 ds->priv = a5psw;
997
998 ret = dsa_register_switch(ds);
999 if (ret) {
1000 dev_err(dev, "Failed to register DSA switch: %d\n", ret);
1001 goto hclk_disable;
1002 }
1003
1004 return 0;
1005
1006hclk_disable:
1007 clk_disable_unprepare(a5psw->hclk);
1008clk_disable:
1009 clk_disable_unprepare(a5psw->clk);
1010free_pcs:
1011 a5psw_pcs_free(a5psw);
1012
1013 return ret;
1014}
1015
1016static int a5psw_remove(struct platform_device *pdev)
1017{
1018 struct a5psw *a5psw = platform_get_drvdata(pdev);
1019
1020 if (!a5psw)
1021 return 0;
1022
1023 dsa_unregister_switch(&a5psw->ds);
1024 a5psw_pcs_free(a5psw);
1025 clk_disable_unprepare(a5psw->hclk);
1026 clk_disable_unprepare(a5psw->clk);
1027
1028 return 0;
1029}
1030
1031static void a5psw_shutdown(struct platform_device *pdev)
1032{
1033 struct a5psw *a5psw = platform_get_drvdata(pdev);
1034
1035 if (!a5psw)
1036 return;
1037
1038 dsa_switch_shutdown(&a5psw->ds);
1039
1040 platform_set_drvdata(pdev, NULL);
1041}
1042
1043static const struct of_device_id a5psw_of_mtable[] = {
1044 { .compatible = "renesas,rzn1-a5psw", },
1045 { /* sentinel */ },
1046};
1047MODULE_DEVICE_TABLE(of, a5psw_of_mtable);
1048
1049static struct platform_driver a5psw_driver = {
1050 .driver = {
1051 .name = "rzn1_a5psw",
1052 .of_match_table = of_match_ptr(a5psw_of_mtable),
1053 },
1054 .probe = a5psw_probe,
1055 .remove = a5psw_remove,
1056 .shutdown = a5psw_shutdown,
1057};
1058module_platform_driver(a5psw_driver);
1059
1060MODULE_LICENSE("GPL");
1061MODULE_DESCRIPTION("Renesas RZ/N1 Advanced 5-port Switch driver");
1062MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");