blob: e99d0a21bd8bc8bccc51fbe65ef52210affbf2a0 [file] [log] [blame]
Florian Fainelli246d7f72014-08-27 17:04:56 -07001/*
2 * Broadcom Starfighter 2 DSA switch driver
3 *
4 * Copyright (C) 2014, Broadcom Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/list.h>
13#include <linux/module.h>
14#include <linux/netdevice.h>
15#include <linux/interrupt.h>
16#include <linux/platform_device.h>
17#include <linux/of.h>
18#include <linux/phy.h>
19#include <linux/phy_fixed.h>
20#include <linux/mii.h>
21#include <linux/of.h>
22#include <linux/of_irq.h>
23#include <linux/of_address.h>
Florian Fainelli8b7c94e2015-10-23 12:11:08 -070024#include <linux/of_net.h>
Florian Fainelli461cd1b02016-06-07 16:32:43 -070025#include <linux/of_mdio.h>
Florian Fainelli246d7f72014-08-27 17:04:56 -070026#include <net/dsa.h>
Florian Fainelli96e65d72014-09-18 17:31:25 -070027#include <linux/ethtool.h>
Florian Fainelli12f460f2015-02-24 13:15:34 -080028#include <linux/if_bridge.h>
Florian Fainelliaafc66f2015-06-10 18:08:01 -070029#include <linux/brcmphy.h>
Florian Fainelli680060d2015-10-23 11:38:07 -070030#include <linux/etherdevice.h>
31#include <net/switchdev.h>
Florian Fainellif4589952016-08-26 12:18:33 -070032#include <linux/platform_data/b53.h>
Florian Fainelli246d7f72014-08-27 17:04:56 -070033
34#include "bcm_sf2.h"
35#include "bcm_sf2_regs.h"
Florian Fainellif4589952016-08-26 12:18:33 -070036#include "b53/b53_priv.h"
37#include "b53/b53_regs.h"
Florian Fainelli246d7f72014-08-27 17:04:56 -070038
39/* String, offset, and register size in bytes if different from 4 bytes */
40static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
41 { "TxOctets", 0x000, 8 },
42 { "TxDropPkts", 0x020 },
43 { "TxQPKTQ0", 0x030 },
44 { "TxBroadcastPkts", 0x040 },
45 { "TxMulticastPkts", 0x050 },
46 { "TxUnicastPKts", 0x060 },
47 { "TxCollisions", 0x070 },
48 { "TxSingleCollision", 0x080 },
49 { "TxMultipleCollision", 0x090 },
50 { "TxDeferredCollision", 0x0a0 },
51 { "TxLateCollision", 0x0b0 },
52 { "TxExcessiveCollision", 0x0c0 },
53 { "TxFrameInDisc", 0x0d0 },
54 { "TxPausePkts", 0x0e0 },
55 { "TxQPKTQ1", 0x0f0 },
56 { "TxQPKTQ2", 0x100 },
57 { "TxQPKTQ3", 0x110 },
58 { "TxQPKTQ4", 0x120 },
59 { "TxQPKTQ5", 0x130 },
60 { "RxOctets", 0x140, 8 },
61 { "RxUndersizePkts", 0x160 },
62 { "RxPausePkts", 0x170 },
63 { "RxPkts64Octets", 0x180 },
64 { "RxPkts65to127Octets", 0x190 },
65 { "RxPkts128to255Octets", 0x1a0 },
66 { "RxPkts256to511Octets", 0x1b0 },
67 { "RxPkts512to1023Octets", 0x1c0 },
68 { "RxPkts1024toMaxPktsOctets", 0x1d0 },
69 { "RxOversizePkts", 0x1e0 },
70 { "RxJabbers", 0x1f0 },
71 { "RxAlignmentErrors", 0x200 },
72 { "RxFCSErrors", 0x210 },
73 { "RxGoodOctets", 0x220, 8 },
74 { "RxDropPkts", 0x240 },
75 { "RxUnicastPkts", 0x250 },
76 { "RxMulticastPkts", 0x260 },
77 { "RxBroadcastPkts", 0x270 },
78 { "RxSAChanges", 0x280 },
79 { "RxFragments", 0x290 },
80 { "RxJumboPkt", 0x2a0 },
81 { "RxSymblErr", 0x2b0 },
82 { "InRangeErrCount", 0x2c0 },
83 { "OutRangeErrCount", 0x2d0 },
84 { "EEELpiEvent", 0x2e0 },
85 { "EEELpiDuration", 0x2f0 },
86 { "RxDiscard", 0x300, 8 },
87 { "TxQPKTQ6", 0x320 },
88 { "TxQPKTQ7", 0x330 },
89 { "TxPkts64Octets", 0x340 },
90 { "TxPkts65to127Octets", 0x350 },
91 { "TxPkts128to255Octets", 0x360 },
92 { "TxPkts256to511Ocets", 0x370 },
93 { "TxPkts512to1023Ocets", 0x380 },
94 { "TxPkts1024toMaxPktOcets", 0x390 },
95};
96
97#define BCM_SF2_STATS_SIZE ARRAY_SIZE(bcm_sf2_mib)
98
99static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
100 int port, uint8_t *data)
101{
102 unsigned int i;
103
104 for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
105 memcpy(data + i * ETH_GSTRING_LEN,
106 bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
107}
108
109static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
110 int port, uint64_t *data)
111{
Florian Fainellif4589952016-08-26 12:18:33 -0700112 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700113 const struct bcm_sf2_hw_stats *s;
114 unsigned int i;
115 u64 val = 0;
116 u32 offset;
117
118 mutex_lock(&priv->stats_mutex);
119
120 /* Now fetch the per-port counters */
121 for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
122 s = &bcm_sf2_mib[i];
123
124 /* Do a latched 64-bit read if needed */
125 offset = s->reg + CORE_P_MIB_OFFSET(port);
126 if (s->sizeof_stat == 8)
127 val = core_readq(priv, offset);
128 else
129 val = core_readl(priv, offset);
130
131 data[i] = (u64)val;
132 }
133
134 mutex_unlock(&priv->stats_mutex);
135}
136
137static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
138{
139 return BCM_SF2_STATS_SIZE;
140}
141
Andrew Lunn7b314362016-08-22 16:01:01 +0200142static enum dsa_tag_protocol bcm_sf2_sw_get_tag_protocol(struct dsa_switch *ds)
143{
144 return DSA_TAG_PROTO_BRCM;
145}
146
Florian Fainellib6d045d2014-09-24 17:05:20 -0700147static void bcm_sf2_imp_vlan_setup(struct dsa_switch *ds, int cpu_port)
Florian Fainelli246d7f72014-08-27 17:04:56 -0700148{
Florian Fainellif4589952016-08-26 12:18:33 -0700149 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700150 unsigned int i;
Florian Fainellib6d045d2014-09-24 17:05:20 -0700151 u32 reg;
152
153 /* Enable the IMP Port to be in the same VLAN as the other ports
154 * on a per-port basis such that we only have Port i and IMP in
155 * the same VLAN.
156 */
157 for (i = 0; i < priv->hw_params.num_ports; i++) {
Andrew Lunn74c3e2a2016-04-13 02:40:44 +0200158 if (!((1 << i) & ds->enabled_port_mask))
Florian Fainellib6d045d2014-09-24 17:05:20 -0700159 continue;
160
161 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
162 reg |= (1 << cpu_port);
163 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
164 }
165}
166
167static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
168{
Florian Fainellif4589952016-08-26 12:18:33 -0700169 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700170 u32 reg, val;
171
172 /* Enable the port memories */
173 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
174 reg &= ~P_TXQ_PSM_VDD(port);
175 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
176
177 /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
178 reg = core_readl(priv, CORE_IMP_CTL);
179 reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
180 reg &= ~(RX_DIS | TX_DIS);
181 core_writel(priv, reg, CORE_IMP_CTL);
182
183 /* Enable forwarding */
184 core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
185
186 /* Enable IMP port in dumb mode */
187 reg = core_readl(priv, CORE_SWITCH_CTRL);
188 reg |= MII_DUMB_FWDG_EN;
189 core_writel(priv, reg, CORE_SWITCH_CTRL);
190
191 /* Resolve which bit controls the Broadcom tag */
192 switch (port) {
193 case 8:
194 val = BRCM_HDR_EN_P8;
195 break;
196 case 7:
197 val = BRCM_HDR_EN_P7;
198 break;
199 case 5:
200 val = BRCM_HDR_EN_P5;
201 break;
202 default:
203 val = 0;
204 break;
205 }
206
207 /* Enable Broadcom tags for IMP port */
208 reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
209 reg |= val;
210 core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
211
212 /* Enable reception Broadcom tag for CPU TX (switch RX) to
213 * allow us to tag outgoing frames
214 */
215 reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
216 reg &= ~(1 << port);
217 core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
218
219 /* Enable transmission of Broadcom tags from the switch (CPU RX) to
220 * allow delivering frames to the per-port net_devices
221 */
222 reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
223 reg &= ~(1 << port);
224 core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
225
226 /* Force link status for IMP port */
227 reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
228 reg |= (MII_SW_OR | LINK_STS);
229 core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700230}
231
Florian Fainelli450b05c2014-09-24 17:05:22 -0700232static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
233{
Florian Fainellif4589952016-08-26 12:18:33 -0700234 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli450b05c2014-09-24 17:05:22 -0700235 u32 reg;
236
237 reg = core_readl(priv, CORE_EEE_EN_CTRL);
238 if (enable)
239 reg |= 1 << port;
240 else
241 reg &= ~(1 << port);
242 core_writel(priv, reg, CORE_EEE_EN_CTRL);
243}
244
Florian Fainellib0836682015-02-05 11:40:41 -0800245static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
246{
Florian Fainellif4589952016-08-26 12:18:33 -0700247 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainellib0836682015-02-05 11:40:41 -0800248 u32 reg;
249
Florian Fainelli9af197a2015-02-05 11:40:42 -0800250 reg = reg_readl(priv, REG_SPHY_CNTRL);
251 if (enable) {
252 reg |= PHY_RESET;
253 reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS);
254 reg_writel(priv, reg, REG_SPHY_CNTRL);
255 udelay(21);
256 reg = reg_readl(priv, REG_SPHY_CNTRL);
257 reg &= ~PHY_RESET;
258 } else {
259 reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET;
260 reg_writel(priv, reg, REG_SPHY_CNTRL);
261 mdelay(1);
262 reg |= CK25_DIS;
263 }
264 reg_writel(priv, reg, REG_SPHY_CNTRL);
Florian Fainellib0836682015-02-05 11:40:41 -0800265
Florian Fainelli9af197a2015-02-05 11:40:42 -0800266 /* Use PHY-driven LED signaling */
267 if (!enable) {
268 reg = reg_readl(priv, REG_LED_CNTRL(0));
269 reg |= SPDLNK_SRC_SEL;
270 reg_writel(priv, reg, REG_LED_CNTRL(0));
271 }
Florian Fainellib0836682015-02-05 11:40:41 -0800272}
273
Florian Fainelli8b7c94e2015-10-23 12:11:08 -0700274static inline void bcm_sf2_port_intr_enable(struct bcm_sf2_priv *priv,
275 int port)
276{
277 unsigned int off;
278
279 switch (port) {
280 case 7:
281 off = P7_IRQ_OFF;
282 break;
283 case 0:
284 /* Port 0 interrupts are located on the first bank */
285 intrl2_0_mask_clear(priv, P_IRQ_MASK(P0_IRQ_OFF));
286 return;
287 default:
288 off = P_IRQ_OFF(port);
289 break;
290 }
291
292 intrl2_1_mask_clear(priv, P_IRQ_MASK(off));
293}
294
295static inline void bcm_sf2_port_intr_disable(struct bcm_sf2_priv *priv,
296 int port)
297{
298 unsigned int off;
299
300 switch (port) {
301 case 7:
302 off = P7_IRQ_OFF;
303 break;
304 case 0:
305 /* Port 0 interrupts are located on the first bank */
306 intrl2_0_mask_set(priv, P_IRQ_MASK(P0_IRQ_OFF));
307 intrl2_0_writel(priv, P_IRQ_MASK(P0_IRQ_OFF), INTRL2_CPU_CLEAR);
308 return;
309 default:
310 off = P_IRQ_OFF(port);
311 break;
312 }
313
314 intrl2_1_mask_set(priv, P_IRQ_MASK(off));
315 intrl2_1_writel(priv, P_IRQ_MASK(off), INTRL2_CPU_CLEAR);
316}
317
Florian Fainellib6d045d2014-09-24 17:05:20 -0700318static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
319 struct phy_device *phy)
Florian Fainelli246d7f72014-08-27 17:04:56 -0700320{
Florian Fainellif4589952016-08-26 12:18:33 -0700321 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainellib6d045d2014-09-24 17:05:20 -0700322 s8 cpu_port = ds->dst[ds->index].cpu_port;
Florian Fainelli246d7f72014-08-27 17:04:56 -0700323 u32 reg;
324
325 /* Clear the memory power down */
326 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
327 reg &= ~P_TXQ_PSM_VDD(port);
328 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
329
330 /* Clear the Rx and Tx disable bits and set to no spanning tree */
331 core_writel(priv, 0, CORE_G_PCTL_PORT(port));
332
Florian Fainelli9af197a2015-02-05 11:40:42 -0800333 /* Re-enable the GPHY and re-apply workarounds */
Florian Fainelli8b7c94e2015-10-23 12:11:08 -0700334 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1) {
Florian Fainelli9af197a2015-02-05 11:40:42 -0800335 bcm_sf2_gphy_enable_set(ds, true);
336 if (phy) {
337 /* if phy_stop() has been called before, phy
338 * will be in halted state, and phy_start()
339 * will call resume.
340 *
341 * the resume path does not configure back
342 * autoneg settings, and since we hard reset
343 * the phy manually here, we need to reset the
344 * state machine also.
345 */
346 phy->state = PHY_READY;
347 phy_init_hw(phy);
348 }
349 }
350
Florian Fainelli8b7c94e2015-10-23 12:11:08 -0700351 /* Enable MoCA port interrupts to get notified */
352 if (port == priv->moca_port)
353 bcm_sf2_port_intr_enable(priv, port);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700354
Florian Fainelli12f460f2015-02-24 13:15:34 -0800355 /* Set this port, and only this one to be in the default VLAN,
356 * if member of a bridge, restore its membership prior to
357 * bringing down this port.
358 */
Florian Fainelli246d7f72014-08-27 17:04:56 -0700359 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
360 reg &= ~PORT_VLAN_CTRL_MASK;
361 reg |= (1 << port);
Florian Fainelli12f460f2015-02-24 13:15:34 -0800362 reg |= priv->port_sts[port].vlan_ctl_mask;
Florian Fainelli246d7f72014-08-27 17:04:56 -0700363 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
Florian Fainellib6d045d2014-09-24 17:05:20 -0700364
365 bcm_sf2_imp_vlan_setup(ds, cpu_port);
366
Florian Fainelli450b05c2014-09-24 17:05:22 -0700367 /* If EEE was enabled, restore it */
368 if (priv->port_sts[port].eee.eee_enabled)
369 bcm_sf2_eee_enable_set(ds, port, true);
370
Florian Fainellib6d045d2014-09-24 17:05:20 -0700371 return 0;
Florian Fainelli246d7f72014-08-27 17:04:56 -0700372}
373
Florian Fainellib6d045d2014-09-24 17:05:20 -0700374static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
375 struct phy_device *phy)
Florian Fainelli246d7f72014-08-27 17:04:56 -0700376{
Florian Fainellif4589952016-08-26 12:18:33 -0700377 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -0700378 u32 off, reg;
379
Florian Fainelli96e65d72014-09-18 17:31:25 -0700380 if (priv->wol_ports_mask & (1 << port))
381 return;
382
Florian Fainelli8b7c94e2015-10-23 12:11:08 -0700383 if (port == priv->moca_port)
384 bcm_sf2_port_intr_disable(priv, port);
Florian Fainellib6d045d2014-09-24 17:05:20 -0700385
Florian Fainelli8b7c94e2015-10-23 12:11:08 -0700386 if (priv->int_phy_mask & 1 << port && priv->hw_params.num_gphy == 1)
Florian Fainelli9af197a2015-02-05 11:40:42 -0800387 bcm_sf2_gphy_enable_set(ds, false);
388
Florian Fainelli246d7f72014-08-27 17:04:56 -0700389 if (dsa_is_cpu_port(ds, port))
390 off = CORE_IMP_CTL;
391 else
392 off = CORE_G_PCTL_PORT(port);
393
394 reg = core_readl(priv, off);
395 reg |= RX_DIS | TX_DIS;
396 core_writel(priv, reg, off);
397
398 /* Power down the port memory */
399 reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
400 reg |= P_TXQ_PSM_VDD(port);
401 core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
402}
403
Florian Fainelli450b05c2014-09-24 17:05:22 -0700404/* Returns 0 if EEE was not enabled, or 1 otherwise
405 */
406static int bcm_sf2_eee_init(struct dsa_switch *ds, int port,
407 struct phy_device *phy)
408{
Florian Fainellif4589952016-08-26 12:18:33 -0700409 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli450b05c2014-09-24 17:05:22 -0700410 struct ethtool_eee *p = &priv->port_sts[port].eee;
411 int ret;
412
413 p->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full);
414
415 ret = phy_init_eee(phy, 0);
416 if (ret)
417 return 0;
418
419 bcm_sf2_eee_enable_set(ds, port, true);
420
421 return 1;
422}
423
424static int bcm_sf2_sw_get_eee(struct dsa_switch *ds, int port,
425 struct ethtool_eee *e)
426{
Florian Fainellif4589952016-08-26 12:18:33 -0700427 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli450b05c2014-09-24 17:05:22 -0700428 struct ethtool_eee *p = &priv->port_sts[port].eee;
429 u32 reg;
430
431 reg = core_readl(priv, CORE_EEE_LPI_INDICATE);
432 e->eee_enabled = p->eee_enabled;
433 e->eee_active = !!(reg & (1 << port));
434
435 return 0;
436}
437
438static int bcm_sf2_sw_set_eee(struct dsa_switch *ds, int port,
439 struct phy_device *phydev,
440 struct ethtool_eee *e)
441{
Florian Fainellif4589952016-08-26 12:18:33 -0700442 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli450b05c2014-09-24 17:05:22 -0700443 struct ethtool_eee *p = &priv->port_sts[port].eee;
444
445 p->eee_enabled = e->eee_enabled;
446
447 if (!p->eee_enabled) {
448 bcm_sf2_eee_enable_set(ds, port, false);
449 } else {
450 p->eee_enabled = bcm_sf2_eee_init(ds, port, phydev);
451 if (!p->eee_enabled)
452 return -EOPNOTSUPP;
453 }
454
455 return 0;
456}
457
Florian Fainellia468ef42016-06-09 17:42:05 -0700458static int bcm_sf2_fast_age_op(struct bcm_sf2_priv *priv)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800459{
Florian Fainelli12f460f2015-02-24 13:15:34 -0800460 unsigned int timeout = 1000;
461 u32 reg;
462
Florian Fainelli12f460f2015-02-24 13:15:34 -0800463 reg = core_readl(priv, CORE_FAST_AGE_CTRL);
Florian Fainelli9c57a772016-06-09 17:42:08 -0700464 reg |= EN_AGE_PORT | EN_AGE_VLAN | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800465 core_writel(priv, reg, CORE_FAST_AGE_CTRL);
466
467 do {
468 reg = core_readl(priv, CORE_FAST_AGE_CTRL);
469 if (!(reg & FAST_AGE_STR_DONE))
470 break;
471
472 cpu_relax();
473 } while (timeout--);
474
475 if (!timeout)
476 return -ETIMEDOUT;
477
Florian Fainelli39797a22015-09-05 13:07:27 -0700478 core_writel(priv, 0, CORE_FAST_AGE_CTRL);
479
Florian Fainelli12f460f2015-02-24 13:15:34 -0800480 return 0;
481}
482
Florian Fainellia468ef42016-06-09 17:42:05 -0700483/* Fast-ageing of ARL entries for a given port, equivalent to an ARL
484 * flush for that port.
485 */
486static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port)
487{
Florian Fainellif4589952016-08-26 12:18:33 -0700488 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainellia468ef42016-06-09 17:42:05 -0700489
490 core_writel(priv, port, CORE_FAST_AGE_PORT);
491
492 return bcm_sf2_fast_age_op(priv);
493}
494
Florian Fainelli9c57a772016-06-09 17:42:08 -0700495static int bcm_sf2_sw_fast_age_vlan(struct bcm_sf2_priv *priv, u16 vid)
496{
497 core_writel(priv, vid, CORE_FAST_AGE_VID);
498
499 return bcm_sf2_fast_age_op(priv);
500}
501
502static int bcm_sf2_vlan_op_wait(struct bcm_sf2_priv *priv)
503{
504 unsigned int timeout = 10;
505 u32 reg;
506
507 do {
508 reg = core_readl(priv, CORE_ARLA_VTBL_RWCTRL);
509 if (!(reg & ARLA_VTBL_STDN))
510 return 0;
511
512 usleep_range(1000, 2000);
513 } while (timeout--);
514
515 return -ETIMEDOUT;
516}
517
518static int bcm_sf2_vlan_op(struct bcm_sf2_priv *priv, u8 op)
519{
520 core_writel(priv, ARLA_VTBL_STDN | op, CORE_ARLA_VTBL_RWCTRL);
521
522 return bcm_sf2_vlan_op_wait(priv);
523}
524
525static void bcm_sf2_set_vlan_entry(struct bcm_sf2_priv *priv, u16 vid,
526 struct bcm_sf2_vlan *vlan)
527{
528 int ret;
529
530 core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR);
531 core_writel(priv, vlan->untag << UNTAG_MAP_SHIFT | vlan->members,
532 CORE_ARLA_VTBL_ENTRY);
533
534 ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_WRITE);
535 if (ret)
536 pr_err("failed to write VLAN entry\n");
537}
538
539static int bcm_sf2_get_vlan_entry(struct bcm_sf2_priv *priv, u16 vid,
540 struct bcm_sf2_vlan *vlan)
541{
542 u32 entry;
543 int ret;
544
545 core_writel(priv, vid & VTBL_ADDR_INDEX_MASK, CORE_ARLA_VTBL_ADDR);
546
547 ret = bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_READ);
548 if (ret)
549 return ret;
550
551 entry = core_readl(priv, CORE_ARLA_VTBL_ENTRY);
552 vlan->members = entry & FWD_MAP_MASK;
553 vlan->untag = (entry >> UNTAG_MAP_SHIFT) & UNTAG_MAP_MASK;
554
555 return 0;
556}
557
Florian Fainelli12f460f2015-02-24 13:15:34 -0800558static int bcm_sf2_sw_br_join(struct dsa_switch *ds, int port,
Vivien Didelota6692752016-02-12 12:09:39 -0500559 struct net_device *bridge)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800560{
Florian Fainellif4589952016-08-26 12:18:33 -0700561 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -0700562 s8 cpu_port = ds->dst->cpu_port;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800563 unsigned int i;
564 u32 reg, p_ctl;
565
Florian Fainelli9c57a772016-06-09 17:42:08 -0700566 /* Make this port leave the all VLANs join since we will have proper
567 * VLAN entries from now on
568 */
569 reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN);
570 reg &= ~BIT(port);
571 if ((reg & BIT(cpu_port)) == BIT(cpu_port))
572 reg &= ~BIT(cpu_port);
573 core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN);
574
Vivien Didelota6692752016-02-12 12:09:39 -0500575 priv->port_sts[port].bridge_dev = bridge;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800576 p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
577
578 for (i = 0; i < priv->hw_params.num_ports; i++) {
Vivien Didelota6692752016-02-12 12:09:39 -0500579 if (priv->port_sts[i].bridge_dev != bridge)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800580 continue;
581
582 /* Add this local port to the remote port VLAN control
583 * membership and update the remote port bitmask
584 */
585 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
586 reg |= 1 << port;
587 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
588 priv->port_sts[i].vlan_ctl_mask = reg;
589
590 p_ctl |= 1 << i;
591 }
592
593 /* Configure the local port VLAN control membership to include
594 * remote ports and update the local port bitmask
595 */
596 core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
597 priv->port_sts[port].vlan_ctl_mask = p_ctl;
598
599 return 0;
600}
601
Vivien Didelot16bfa702016-03-13 16:21:33 -0400602static void bcm_sf2_sw_br_leave(struct dsa_switch *ds, int port)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800603{
Florian Fainellif4589952016-08-26 12:18:33 -0700604 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Vivien Didelota6692752016-02-12 12:09:39 -0500605 struct net_device *bridge = priv->port_sts[port].bridge_dev;
Florian Fainelli9c57a772016-06-09 17:42:08 -0700606 s8 cpu_port = ds->dst->cpu_port;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800607 unsigned int i;
608 u32 reg, p_ctl;
609
610 p_ctl = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
611
612 for (i = 0; i < priv->hw_params.num_ports; i++) {
613 /* Don't touch the remaining ports */
Vivien Didelota6692752016-02-12 12:09:39 -0500614 if (priv->port_sts[i].bridge_dev != bridge)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800615 continue;
616
617 reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
618 reg &= ~(1 << port);
619 core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
620 priv->port_sts[port].vlan_ctl_mask = reg;
621
622 /* Prevent self removal to preserve isolation */
623 if (port != i)
624 p_ctl &= ~(1 << i);
625 }
626
627 core_writel(priv, p_ctl, CORE_PORT_VLAN_CTL_PORT(port));
628 priv->port_sts[port].vlan_ctl_mask = p_ctl;
Vivien Didelota6692752016-02-12 12:09:39 -0500629 priv->port_sts[port].bridge_dev = NULL;
Florian Fainelli9c57a772016-06-09 17:42:08 -0700630
631 /* Make this port join all VLANs without VLAN entries */
632 reg = core_readl(priv, CORE_JOIN_ALL_VLAN_EN);
633 reg |= BIT(port);
634 if (!(reg & BIT(cpu_port)))
635 reg |= BIT(cpu_port);
636 core_writel(priv, reg, CORE_JOIN_ALL_VLAN_EN);
Florian Fainelli12f460f2015-02-24 13:15:34 -0800637}
638
Vivien Didelot43c44a92016-04-06 11:55:03 -0400639static void bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port,
640 u8 state)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800641{
Florian Fainellif4589952016-08-26 12:18:33 -0700642 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli12f460f2015-02-24 13:15:34 -0800643 u8 hw_state, cur_hw_state;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800644 u32 reg;
645
646 reg = core_readl(priv, CORE_G_PCTL_PORT(port));
Florian Fainelli39797a22015-09-05 13:07:27 -0700647 cur_hw_state = reg & (G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT);
Florian Fainelli12f460f2015-02-24 13:15:34 -0800648
649 switch (state) {
650 case BR_STATE_DISABLED:
651 hw_state = G_MISTP_DIS_STATE;
652 break;
653 case BR_STATE_LISTENING:
654 hw_state = G_MISTP_LISTEN_STATE;
655 break;
656 case BR_STATE_LEARNING:
657 hw_state = G_MISTP_LEARN_STATE;
658 break;
659 case BR_STATE_FORWARDING:
660 hw_state = G_MISTP_FWD_STATE;
661 break;
662 case BR_STATE_BLOCKING:
663 hw_state = G_MISTP_BLOCK_STATE;
664 break;
665 default:
666 pr_err("%s: invalid STP state: %d\n", __func__, state);
Vivien Didelot43c44a92016-04-06 11:55:03 -0400667 return;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800668 }
669
670 /* Fast-age ARL entries if we are moving a port from Learning or
Florian Fainelli39797a22015-09-05 13:07:27 -0700671 * Forwarding (cur_hw_state) state to Disabled, Blocking or Listening
672 * state (hw_state)
Florian Fainelli12f460f2015-02-24 13:15:34 -0800673 */
674 if (cur_hw_state != hw_state) {
Florian Fainelli39797a22015-09-05 13:07:27 -0700675 if (cur_hw_state >= G_MISTP_LEARN_STATE &&
676 hw_state <= G_MISTP_LISTEN_STATE) {
Vivien Didelot43c44a92016-04-06 11:55:03 -0400677 if (bcm_sf2_sw_fast_age_port(ds, port)) {
Florian Fainelli12f460f2015-02-24 13:15:34 -0800678 pr_err("%s: fast-ageing failed\n", __func__);
Vivien Didelot43c44a92016-04-06 11:55:03 -0400679 return;
Florian Fainelli12f460f2015-02-24 13:15:34 -0800680 }
681 }
682 }
683
684 reg = core_readl(priv, CORE_G_PCTL_PORT(port));
685 reg &= ~(G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT);
686 reg |= hw_state;
687 core_writel(priv, reg, CORE_G_PCTL_PORT(port));
Florian Fainelli12f460f2015-02-24 13:15:34 -0800688}
689
Florian Fainelli680060d2015-10-23 11:38:07 -0700690/* Address Resolution Logic routines */
691static int bcm_sf2_arl_op_wait(struct bcm_sf2_priv *priv)
692{
693 unsigned int timeout = 10;
694 u32 reg;
695
696 do {
697 reg = core_readl(priv, CORE_ARLA_RWCTL);
698 if (!(reg & ARL_STRTDN))
699 return 0;
700
701 usleep_range(1000, 2000);
702 } while (timeout--);
703
704 return -ETIMEDOUT;
705}
706
707static int bcm_sf2_arl_rw_op(struct bcm_sf2_priv *priv, unsigned int op)
708{
709 u32 cmd;
710
711 if (op > ARL_RW)
712 return -EINVAL;
713
714 cmd = core_readl(priv, CORE_ARLA_RWCTL);
715 cmd &= ~IVL_SVL_SELECT;
716 cmd |= ARL_STRTDN;
717 if (op)
718 cmd |= ARL_RW;
719 else
720 cmd &= ~ARL_RW;
721 core_writel(priv, cmd, CORE_ARLA_RWCTL);
722
723 return bcm_sf2_arl_op_wait(priv);
724}
725
726static int bcm_sf2_arl_read(struct bcm_sf2_priv *priv, u64 mac,
727 u16 vid, struct bcm_sf2_arl_entry *ent, u8 *idx,
728 bool is_valid)
729{
730 unsigned int i;
731 int ret;
732
733 ret = bcm_sf2_arl_op_wait(priv);
734 if (ret)
735 return ret;
736
737 /* Read the 4 bins */
738 for (i = 0; i < 4; i++) {
739 u64 mac_vid;
740 u32 fwd_entry;
741
742 mac_vid = core_readq(priv, CORE_ARLA_MACVID_ENTRY(i));
743 fwd_entry = core_readl(priv, CORE_ARLA_FWD_ENTRY(i));
744 bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
745
746 if (ent->is_valid && is_valid) {
747 *idx = i;
748 return 0;
749 }
750
751 /* This is the MAC we just deleted */
752 if (!is_valid && (mac_vid & mac))
753 return 0;
754 }
755
756 return -ENOENT;
757}
758
759static int bcm_sf2_arl_op(struct bcm_sf2_priv *priv, int op, int port,
760 const unsigned char *addr, u16 vid, bool is_valid)
761{
762 struct bcm_sf2_arl_entry ent;
763 u32 fwd_entry;
764 u64 mac, mac_vid = 0;
765 u8 idx = 0;
766 int ret;
767
768 /* Convert the array into a 64-bit MAC */
769 mac = bcm_sf2_mac_to_u64(addr);
770
771 /* Perform a read for the given MAC and VID */
772 core_writeq(priv, mac, CORE_ARLA_MAC);
773 core_writel(priv, vid, CORE_ARLA_VID);
774
775 /* Issue a read operation for this MAC */
776 ret = bcm_sf2_arl_rw_op(priv, 1);
777 if (ret)
778 return ret;
779
780 ret = bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
781 /* If this is a read, just finish now */
782 if (op)
783 return ret;
784
785 /* We could not find a matching MAC, so reset to a new entry */
786 if (ret) {
787 fwd_entry = 0;
788 idx = 0;
789 }
790
791 memset(&ent, 0, sizeof(ent));
792 ent.port = port;
793 ent.is_valid = is_valid;
794 ent.vid = vid;
795 ent.is_static = true;
796 memcpy(ent.mac, addr, ETH_ALEN);
797 bcm_sf2_arl_from_entry(&mac_vid, &fwd_entry, &ent);
798
799 core_writeq(priv, mac_vid, CORE_ARLA_MACVID_ENTRY(idx));
800 core_writel(priv, fwd_entry, CORE_ARLA_FWD_ENTRY(idx));
801
802 ret = bcm_sf2_arl_rw_op(priv, 0);
803 if (ret)
804 return ret;
805
806 /* Re-read the entry to check */
807 return bcm_sf2_arl_read(priv, mac, vid, &ent, &idx, is_valid);
808}
809
810static int bcm_sf2_sw_fdb_prepare(struct dsa_switch *ds, int port,
811 const struct switchdev_obj_port_fdb *fdb,
812 struct switchdev_trans *trans)
813{
814 /* We do not need to do anything specific here yet */
815 return 0;
816}
817
Vivien Didelot8497aa62016-04-06 11:55:04 -0400818static void bcm_sf2_sw_fdb_add(struct dsa_switch *ds, int port,
819 const struct switchdev_obj_port_fdb *fdb,
820 struct switchdev_trans *trans)
Florian Fainelli680060d2015-10-23 11:38:07 -0700821{
Florian Fainellif4589952016-08-26 12:18:33 -0700822 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli680060d2015-10-23 11:38:07 -0700823
Vivien Didelot8497aa62016-04-06 11:55:04 -0400824 if (bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, true))
825 pr_err("%s: failed to add MAC address\n", __func__);
Florian Fainelli680060d2015-10-23 11:38:07 -0700826}
827
828static int bcm_sf2_sw_fdb_del(struct dsa_switch *ds, int port,
829 const struct switchdev_obj_port_fdb *fdb)
830{
Florian Fainellif4589952016-08-26 12:18:33 -0700831 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli680060d2015-10-23 11:38:07 -0700832
833 return bcm_sf2_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
834}
835
836static int bcm_sf2_arl_search_wait(struct bcm_sf2_priv *priv)
837{
838 unsigned timeout = 1000;
839 u32 reg;
840
841 do {
842 reg = core_readl(priv, CORE_ARLA_SRCH_CTL);
843 if (!(reg & ARLA_SRCH_STDN))
844 return 0;
845
846 if (reg & ARLA_SRCH_VLID)
847 return 0;
848
849 usleep_range(1000, 2000);
850 } while (timeout--);
851
852 return -ETIMEDOUT;
853}
854
855static void bcm_sf2_arl_search_rd(struct bcm_sf2_priv *priv, u8 idx,
856 struct bcm_sf2_arl_entry *ent)
857{
858 u64 mac_vid;
859 u32 fwd_entry;
860
861 mac_vid = core_readq(priv, CORE_ARLA_SRCH_RSLT_MACVID(idx));
862 fwd_entry = core_readl(priv, CORE_ARLA_SRCH_RSLT(idx));
863 bcm_sf2_arl_to_entry(ent, mac_vid, fwd_entry);
864}
865
866static int bcm_sf2_sw_fdb_copy(struct net_device *dev, int port,
867 const struct bcm_sf2_arl_entry *ent,
868 struct switchdev_obj_port_fdb *fdb,
869 int (*cb)(struct switchdev_obj *obj))
870{
871 if (!ent->is_valid)
872 return 0;
873
874 if (port != ent->port)
875 return 0;
876
877 ether_addr_copy(fdb->addr, ent->mac);
878 fdb->vid = ent->vid;
879 fdb->ndm_state = ent->is_static ? NUD_NOARP : NUD_REACHABLE;
880
881 return cb(&fdb->obj);
882}
883
884static int bcm_sf2_sw_fdb_dump(struct dsa_switch *ds, int port,
885 struct switchdev_obj_port_fdb *fdb,
886 int (*cb)(struct switchdev_obj *obj))
887{
Florian Fainellif4589952016-08-26 12:18:33 -0700888 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Andrew Lunnc8b09802016-06-04 21:16:57 +0200889 struct net_device *dev = ds->ports[port].netdev;
Florian Fainelli680060d2015-10-23 11:38:07 -0700890 struct bcm_sf2_arl_entry results[2];
891 unsigned int count = 0;
892 int ret;
893
894 /* Start search operation */
895 core_writel(priv, ARLA_SRCH_STDN, CORE_ARLA_SRCH_CTL);
896
897 do {
898 ret = bcm_sf2_arl_search_wait(priv);
899 if (ret)
900 return ret;
901
902 /* Read both entries, then return their values back */
903 bcm_sf2_arl_search_rd(priv, 0, &results[0]);
904 ret = bcm_sf2_sw_fdb_copy(dev, port, &results[0], fdb, cb);
905 if (ret)
906 return ret;
907
908 bcm_sf2_arl_search_rd(priv, 1, &results[1]);
909 ret = bcm_sf2_sw_fdb_copy(dev, port, &results[1], fdb, cb);
910 if (ret)
911 return ret;
912
913 if (!results[0].is_valid && !results[1].is_valid)
914 break;
915
916 } while (count++ < CORE_ARLA_NUM_ENTRIES);
917
918 return 0;
919}
920
Florian Fainelli461cd1b02016-06-07 16:32:43 -0700921static int bcm_sf2_sw_indir_rw(struct bcm_sf2_priv *priv, int op, int addr,
922 int regnum, u16 val)
923{
924 int ret = 0;
925 u32 reg;
926
927 reg = reg_readl(priv, REG_SWITCH_CNTRL);
928 reg |= MDIO_MASTER_SEL;
929 reg_writel(priv, reg, REG_SWITCH_CNTRL);
930
931 /* Page << 8 | offset */
932 reg = 0x70;
933 reg <<= 2;
934 core_writel(priv, addr, reg);
935
936 /* Page << 8 | offset */
937 reg = 0x80 << 8 | regnum << 1;
938 reg <<= 2;
939
940 if (op)
941 ret = core_readl(priv, reg);
942 else
943 core_writel(priv, val, reg);
944
945 reg = reg_readl(priv, REG_SWITCH_CNTRL);
946 reg &= ~MDIO_MASTER_SEL;
947 reg_writel(priv, reg, REG_SWITCH_CNTRL);
948
949 return ret & 0xffff;
950}
951
952static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
953{
954 struct bcm_sf2_priv *priv = bus->priv;
955
956 /* Intercept reads from Broadcom pseudo-PHY address, else, send
957 * them to our master MDIO bus controller
958 */
959 if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
960 return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);
961 else
962 return mdiobus_read(priv->master_mii_bus, addr, regnum);
963}
964
965static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
966 u16 val)
967{
968 struct bcm_sf2_priv *priv = bus->priv;
969
970 /* Intercept writes to the Broadcom pseudo-PHY address, else,
971 * send them to our master MDIO bus controller
972 */
973 if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
974 bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);
975 else
976 mdiobus_write(priv->master_mii_bus, addr, regnum, val);
977
978 return 0;
979}
980
Florian Fainelli246d7f72014-08-27 17:04:56 -0700981static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
982{
983 struct bcm_sf2_priv *priv = dev_id;
984
985 priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
986 ~priv->irq0_mask;
987 intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
988
989 return IRQ_HANDLED;
990}
991
992static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
993{
994 struct bcm_sf2_priv *priv = dev_id;
995
996 priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
997 ~priv->irq1_mask;
998 intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
999
1000 if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
1001 priv->port_sts[7].link = 1;
1002 if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
1003 priv->port_sts[7].link = 0;
1004
1005 return IRQ_HANDLED;
1006}
1007
Florian Fainelli33f84612014-11-25 18:08:49 -08001008static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
1009{
1010 unsigned int timeout = 1000;
1011 u32 reg;
1012
1013 reg = core_readl(priv, CORE_WATCHDOG_CTRL);
1014 reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET;
1015 core_writel(priv, reg, CORE_WATCHDOG_CTRL);
1016
1017 do {
1018 reg = core_readl(priv, CORE_WATCHDOG_CTRL);
1019 if (!(reg & SOFTWARE_RESET))
1020 break;
1021
1022 usleep_range(1000, 2000);
1023 } while (timeout-- > 0);
1024
1025 if (timeout == 0)
1026 return -ETIMEDOUT;
1027
1028 return 0;
1029}
1030
Florian Fainelli691c9a82015-01-20 16:42:00 -08001031static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)
1032{
1033 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
1034 intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
1035 intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
1036 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
1037 intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
1038 intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
1039}
1040
Florian Fainelli8b7c94e2015-10-23 12:11:08 -07001041static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv,
1042 struct device_node *dn)
1043{
1044 struct device_node *port;
1045 const char *phy_mode_str;
1046 int mode;
1047 unsigned int port_num;
1048 int ret;
1049
1050 priv->moca_port = -1;
1051
1052 for_each_available_child_of_node(dn, port) {
1053 if (of_property_read_u32(port, "reg", &port_num))
1054 continue;
1055
1056 /* Internal PHYs get assigned a specific 'phy-mode' property
1057 * value: "internal" to help flag them before MDIO probing
1058 * has completed, since they might be turned off at that
1059 * time
1060 */
1061 mode = of_get_phy_mode(port);
1062 if (mode < 0) {
1063 ret = of_property_read_string(port, "phy-mode",
1064 &phy_mode_str);
1065 if (ret < 0)
1066 continue;
1067
1068 if (!strcasecmp(phy_mode_str, "internal"))
1069 priv->int_phy_mask |= 1 << port_num;
1070 }
1071
1072 if (mode == PHY_INTERFACE_MODE_MOCA)
1073 priv->moca_port = port_num;
1074 }
1075}
1076
Florian Fainelli461cd1b02016-06-07 16:32:43 -07001077static int bcm_sf2_mdio_register(struct dsa_switch *ds)
1078{
Florian Fainellif4589952016-08-26 12:18:33 -07001079 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli461cd1b02016-06-07 16:32:43 -07001080 struct device_node *dn;
1081 static int index;
1082 int err;
1083
1084 /* Find our integrated MDIO bus node */
1085 dn = of_find_compatible_node(NULL, NULL, "brcm,unimac-mdio");
1086 priv->master_mii_bus = of_mdio_find_bus(dn);
1087 if (!priv->master_mii_bus)
1088 return -EPROBE_DEFER;
1089
1090 get_device(&priv->master_mii_bus->dev);
1091 priv->master_mii_dn = dn;
1092
1093 priv->slave_mii_bus = devm_mdiobus_alloc(ds->dev);
1094 if (!priv->slave_mii_bus)
1095 return -ENOMEM;
1096
1097 priv->slave_mii_bus->priv = priv;
1098 priv->slave_mii_bus->name = "sf2 slave mii";
1099 priv->slave_mii_bus->read = bcm_sf2_sw_mdio_read;
1100 priv->slave_mii_bus->write = bcm_sf2_sw_mdio_write;
1101 snprintf(priv->slave_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",
1102 index++);
1103 priv->slave_mii_bus->dev.of_node = dn;
1104
1105 /* Include the pseudo-PHY address to divert reads towards our
1106 * workaround. This is only required for 7445D0, since 7445E0
1107 * disconnects the internal switch pseudo-PHY such that we can use the
1108 * regular SWITCH_MDIO master controller instead.
1109 *
1110 * Here we flag the pseudo PHY as needing special treatment and would
1111 * otherwise make all other PHY read/writes go to the master MDIO bus
1112 * controller that comes with this switch backed by the "mdio-unimac"
1113 * driver.
1114 */
1115 if (of_machine_is_compatible("brcm,bcm7445d0"))
1116 priv->indir_phy_mask |= (1 << BRCM_PSEUDO_PHY_ADDR);
1117 else
1118 priv->indir_phy_mask = 0;
1119
1120 ds->phys_mii_mask = priv->indir_phy_mask;
1121 ds->slave_mii_bus = priv->slave_mii_bus;
1122 priv->slave_mii_bus->parent = ds->dev->parent;
1123 priv->slave_mii_bus->phy_mask = ~priv->indir_phy_mask;
1124
1125 if (dn)
1126 err = of_mdiobus_register(priv->slave_mii_bus, dn);
1127 else
1128 err = mdiobus_register(priv->slave_mii_bus);
1129
1130 if (err)
1131 of_node_put(dn);
1132
1133 return err;
1134}
1135
1136static void bcm_sf2_mdio_unregister(struct bcm_sf2_priv *priv)
1137{
1138 mdiobus_unregister(priv->slave_mii_bus);
1139 if (priv->master_mii_dn)
1140 of_node_put(priv->master_mii_dn);
1141}
1142
Florian Fainelli246d7f72014-08-27 17:04:56 -07001143static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
1144{
1145 return 0;
1146}
1147
Florian Fainelliaa9aef72014-09-19 13:07:55 -07001148static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
1149{
Florian Fainellif4589952016-08-26 12:18:33 -07001150 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelliaa9aef72014-09-19 13:07:55 -07001151
1152 /* The BCM7xxx PHY driver expects to find the integrated PHY revision
1153 * in bits 15:8 and the patch level in bits 7:0 which is exactly what
1154 * the REG_PHY_REVISION register layout is.
1155 */
1156
1157 return priv->hw_params.gphy_rev;
1158}
1159
Florian Fainelli246d7f72014-08-27 17:04:56 -07001160static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
1161 struct phy_device *phydev)
1162{
Florian Fainellif4589952016-08-26 12:18:33 -07001163 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001164 u32 id_mode_dis = 0, port_mode;
1165 const char *str = NULL;
1166 u32 reg;
1167
1168 switch (phydev->interface) {
1169 case PHY_INTERFACE_MODE_RGMII:
1170 str = "RGMII (no delay)";
1171 id_mode_dis = 1;
1172 case PHY_INTERFACE_MODE_RGMII_TXID:
1173 if (!str)
1174 str = "RGMII (TX delay)";
1175 port_mode = EXT_GPHY;
1176 break;
1177 case PHY_INTERFACE_MODE_MII:
1178 str = "MII";
1179 port_mode = EXT_EPHY;
1180 break;
1181 case PHY_INTERFACE_MODE_REVMII:
1182 str = "Reverse MII";
1183 port_mode = EXT_REVMII;
1184 break;
1185 default:
Florian Fainelli7de15572014-09-24 17:05:19 -07001186 /* All other PHYs: internal and MoCA */
1187 goto force_link;
1188 }
1189
1190 /* If the link is down, just disable the interface to conserve power */
1191 if (!phydev->link) {
1192 reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
1193 reg &= ~RGMII_MODE_EN;
1194 reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
Florian Fainelli246d7f72014-08-27 17:04:56 -07001195 goto force_link;
1196 }
1197
1198 /* Clear id_mode_dis bit, and the existing port mode, but
1199 * make sure we enable the RGMII block for data to pass
1200 */
1201 reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
1202 reg &= ~ID_MODE_DIS;
1203 reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
1204 reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
1205
1206 reg |= port_mode | RGMII_MODE_EN;
1207 if (id_mode_dis)
1208 reg |= ID_MODE_DIS;
1209
1210 if (phydev->pause) {
1211 if (phydev->asym_pause)
1212 reg |= TX_PAUSE_EN;
1213 reg |= RX_PAUSE_EN;
1214 }
1215
1216 reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
1217
1218 pr_info("Port %d configured for %s\n", port, str);
1219
1220force_link:
1221 /* Force link settings detected from the PHY */
1222 reg = SW_OVERRIDE;
1223 switch (phydev->speed) {
1224 case SPEED_1000:
1225 reg |= SPDSTS_1000 << SPEED_SHIFT;
1226 break;
1227 case SPEED_100:
1228 reg |= SPDSTS_100 << SPEED_SHIFT;
1229 break;
1230 }
1231
1232 if (phydev->link)
1233 reg |= LINK_STS;
1234 if (phydev->duplex == DUPLEX_FULL)
1235 reg |= DUPLX_MODE;
1236
1237 core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
1238}
1239
1240static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
1241 struct fixed_phy_status *status)
1242{
Florian Fainellif4589952016-08-26 12:18:33 -07001243 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainellid2eac982015-07-20 17:49:55 -07001244 u32 duplex, pause;
Florian Fainelli246d7f72014-08-27 17:04:56 -07001245 u32 reg;
1246
Florian Fainelli246d7f72014-08-27 17:04:56 -07001247 duplex = core_readl(priv, CORE_DUPSTS);
1248 pause = core_readl(priv, CORE_PAUSESTS);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001249
1250 status->link = 0;
1251
Florian Fainelli8b7c94e2015-10-23 12:11:08 -07001252 /* MoCA port is special as we do not get link status from CORE_LNKSTS,
Florian Fainelli246d7f72014-08-27 17:04:56 -07001253 * which means that we need to force the link at the port override
1254 * level to get the data to flow. We do use what the interrupt handler
1255 * did determine before.
Florian Fainelli7855f672014-12-11 18:12:42 -08001256 *
1257 * For the other ports, we just force the link status, since this is
1258 * a fixed PHY device.
Florian Fainelli246d7f72014-08-27 17:04:56 -07001259 */
Florian Fainelli8b7c94e2015-10-23 12:11:08 -07001260 if (port == priv->moca_port) {
Florian Fainelli246d7f72014-08-27 17:04:56 -07001261 status->link = priv->port_sts[port].link;
Florian Fainelli4ab7f912015-05-15 12:38:01 -07001262 /* For MoCA interfaces, also force a link down notification
1263 * since some version of the user-space daemon (mocad) use
1264 * cmd->autoneg to force the link, which messes up the PHY
1265 * state machine and make it go in PHY_FORCING state instead.
1266 */
1267 if (!status->link)
Andrew Lunnc8b09802016-06-04 21:16:57 +02001268 netif_carrier_off(ds->ports[port].netdev);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001269 status->duplex = 1;
1270 } else {
Florian Fainelli7855f672014-12-11 18:12:42 -08001271 status->link = 1;
Florian Fainelli246d7f72014-08-27 17:04:56 -07001272 status->duplex = !!(duplex & (1 << port));
1273 }
1274
Florian Fainelli7855f672014-12-11 18:12:42 -08001275 reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(port));
1276 reg |= SW_OVERRIDE;
1277 if (status->link)
1278 reg |= LINK_STS;
1279 else
1280 reg &= ~LINK_STS;
1281 core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
1282
Florian Fainelli246d7f72014-08-27 17:04:56 -07001283 if ((pause & (1 << port)) &&
1284 (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
1285 status->asym_pause = 1;
1286 status->pause = 1;
1287 }
1288
1289 if (pause & (1 << port))
1290 status->pause = 1;
1291}
1292
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001293static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
1294{
Florian Fainellif4589952016-08-26 12:18:33 -07001295 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001296 unsigned int port;
1297
Florian Fainelli691c9a82015-01-20 16:42:00 -08001298 bcm_sf2_intr_disable(priv);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001299
1300 /* Disable all ports physically present including the IMP
1301 * port, the other ones have already been disabled during
1302 * bcm_sf2_sw_setup
1303 */
1304 for (port = 0; port < DSA_MAX_PORTS; port++) {
Andrew Lunn74c3e2a2016-04-13 02:40:44 +02001305 if ((1 << port) & ds->enabled_port_mask ||
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001306 dsa_is_cpu_port(ds, port))
Florian Fainellib6d045d2014-09-24 17:05:20 -07001307 bcm_sf2_port_disable(ds, port, NULL);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001308 }
1309
1310 return 0;
1311}
1312
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001313static int bcm_sf2_sw_resume(struct dsa_switch *ds)
1314{
Florian Fainellif4589952016-08-26 12:18:33 -07001315 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001316 unsigned int port;
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001317 int ret;
1318
1319 ret = bcm_sf2_sw_rst(priv);
1320 if (ret) {
1321 pr_err("%s: failed to software reset switch\n", __func__);
1322 return ret;
1323 }
1324
Florian Fainellib0836682015-02-05 11:40:41 -08001325 if (priv->hw_params.num_gphy == 1)
1326 bcm_sf2_gphy_enable_set(ds, true);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001327
1328 for (port = 0; port < DSA_MAX_PORTS; port++) {
Andrew Lunn74c3e2a2016-04-13 02:40:44 +02001329 if ((1 << port) & ds->enabled_port_mask)
Florian Fainellib6d045d2014-09-24 17:05:20 -07001330 bcm_sf2_port_setup(ds, port, NULL);
Florian Fainelli8cfa9492014-09-18 17:31:23 -07001331 else if (dsa_is_cpu_port(ds, port))
1332 bcm_sf2_imp_setup(ds, port);
1333 }
1334
1335 return 0;
1336}
1337
Florian Fainelli96e65d72014-09-18 17:31:25 -07001338static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port,
1339 struct ethtool_wolinfo *wol)
1340{
1341 struct net_device *p = ds->dst[ds->index].master_netdev;
Florian Fainellif4589952016-08-26 12:18:33 -07001342 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli96e65d72014-09-18 17:31:25 -07001343 struct ethtool_wolinfo pwol;
1344
1345 /* Get the parent device WoL settings */
1346 p->ethtool_ops->get_wol(p, &pwol);
1347
1348 /* Advertise the parent device supported settings */
1349 wol->supported = pwol.supported;
1350 memset(&wol->sopass, 0, sizeof(wol->sopass));
1351
1352 if (pwol.wolopts & WAKE_MAGICSECURE)
1353 memcpy(&wol->sopass, pwol.sopass, sizeof(wol->sopass));
1354
1355 if (priv->wol_ports_mask & (1 << port))
1356 wol->wolopts = pwol.wolopts;
1357 else
1358 wol->wolopts = 0;
1359}
1360
1361static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port,
1362 struct ethtool_wolinfo *wol)
1363{
1364 struct net_device *p = ds->dst[ds->index].master_netdev;
Florian Fainellif4589952016-08-26 12:18:33 -07001365 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli96e65d72014-09-18 17:31:25 -07001366 s8 cpu_port = ds->dst[ds->index].cpu_port;
1367 struct ethtool_wolinfo pwol;
1368
1369 p->ethtool_ops->get_wol(p, &pwol);
1370 if (wol->wolopts & ~pwol.supported)
1371 return -EINVAL;
1372
1373 if (wol->wolopts)
1374 priv->wol_ports_mask |= (1 << port);
1375 else
1376 priv->wol_ports_mask &= ~(1 << port);
1377
1378 /* If we have at least one port enabled, make sure the CPU port
1379 * is also enabled. If the CPU port is the last one enabled, we disable
1380 * it since this configuration does not make sense.
1381 */
1382 if (priv->wol_ports_mask && priv->wol_ports_mask != (1 << cpu_port))
1383 priv->wol_ports_mask |= (1 << cpu_port);
1384 else
1385 priv->wol_ports_mask &= ~(1 << cpu_port);
1386
1387 return p->ethtool_ops->set_wol(p, wol);
1388}
1389
Florian Fainelli9c57a772016-06-09 17:42:08 -07001390static void bcm_sf2_enable_vlan(struct bcm_sf2_priv *priv, bool enable)
1391{
1392 u32 mgmt, vc0, vc1, vc4, vc5;
1393
1394 mgmt = core_readl(priv, CORE_SWMODE);
1395 vc0 = core_readl(priv, CORE_VLAN_CTRL0);
1396 vc1 = core_readl(priv, CORE_VLAN_CTRL1);
1397 vc4 = core_readl(priv, CORE_VLAN_CTRL4);
1398 vc5 = core_readl(priv, CORE_VLAN_CTRL5);
1399
1400 mgmt &= ~SW_FWDG_MODE;
1401
1402 if (enable) {
1403 vc0 |= VLAN_EN | VLAN_LEARN_MODE_IVL;
1404 vc1 |= EN_RSV_MCAST_UNTAG | EN_RSV_MCAST_FWDMAP;
1405 vc4 &= ~(INGR_VID_CHK_MASK << INGR_VID_CHK_SHIFT);
1406 vc4 |= INGR_VID_CHK_DROP;
1407 vc5 |= DROP_VTABLE_MISS | EN_VID_FFF_FWD;
1408 } else {
1409 vc0 &= ~(VLAN_EN | VLAN_LEARN_MODE_IVL);
1410 vc1 &= ~(EN_RSV_MCAST_UNTAG | EN_RSV_MCAST_FWDMAP);
1411 vc4 &= ~(INGR_VID_CHK_MASK << INGR_VID_CHK_SHIFT);
1412 vc5 &= ~(DROP_VTABLE_MISS | EN_VID_FFF_FWD);
1413 vc4 |= INGR_VID_CHK_VID_VIOL_IMP;
1414 }
1415
1416 core_writel(priv, vc0, CORE_VLAN_CTRL0);
1417 core_writel(priv, vc1, CORE_VLAN_CTRL1);
1418 core_writel(priv, 0, CORE_VLAN_CTRL3);
1419 core_writel(priv, vc4, CORE_VLAN_CTRL4);
1420 core_writel(priv, vc5, CORE_VLAN_CTRL5);
1421 core_writel(priv, mgmt, CORE_SWMODE);
1422}
1423
1424static void bcm_sf2_sw_configure_vlan(struct dsa_switch *ds)
1425{
Florian Fainellif4589952016-08-26 12:18:33 -07001426 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -07001427 unsigned int port;
1428
1429 /* Clear all VLANs */
1430 bcm_sf2_vlan_op(priv, ARLA_VTBL_CMD_CLEAR);
1431
1432 for (port = 0; port < priv->hw_params.num_ports; port++) {
1433 if (!((1 << port) & ds->enabled_port_mask))
1434 continue;
1435
1436 core_writel(priv, 1, CORE_DEFAULT_1Q_TAG_P(port));
1437 }
1438}
1439
1440static int bcm_sf2_sw_vlan_filtering(struct dsa_switch *ds, int port,
1441 bool vlan_filtering)
1442{
1443 return 0;
1444}
1445
1446static int bcm_sf2_sw_vlan_prepare(struct dsa_switch *ds, int port,
1447 const struct switchdev_obj_port_vlan *vlan,
1448 struct switchdev_trans *trans)
1449{
Florian Fainellif4589952016-08-26 12:18:33 -07001450 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -07001451
1452 bcm_sf2_enable_vlan(priv, true);
1453
1454 return 0;
1455}
1456
1457static void bcm_sf2_sw_vlan_add(struct dsa_switch *ds, int port,
1458 const struct switchdev_obj_port_vlan *vlan,
1459 struct switchdev_trans *trans)
1460{
Florian Fainellif4589952016-08-26 12:18:33 -07001461 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -07001462 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1463 bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1464 s8 cpu_port = ds->dst->cpu_port;
1465 struct bcm_sf2_vlan *vl;
1466 u16 vid;
1467
1468 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1469 vl = &priv->vlans[vid];
1470
1471 bcm_sf2_get_vlan_entry(priv, vid, vl);
1472
1473 vl->members |= BIT(port) | BIT(cpu_port);
1474 if (untagged)
1475 vl->untag |= BIT(port) | BIT(cpu_port);
1476 else
1477 vl->untag &= ~(BIT(port) | BIT(cpu_port));
1478
1479 bcm_sf2_set_vlan_entry(priv, vid, vl);
1480 bcm_sf2_sw_fast_age_vlan(priv, vid);
1481 }
1482
1483 if (pvid) {
1484 core_writel(priv, vlan->vid_end, CORE_DEFAULT_1Q_TAG_P(port));
1485 core_writel(priv, vlan->vid_end,
1486 CORE_DEFAULT_1Q_TAG_P(cpu_port));
1487 bcm_sf2_sw_fast_age_vlan(priv, vid);
1488 }
1489}
1490
1491static int bcm_sf2_sw_vlan_del(struct dsa_switch *ds, int port,
1492 const struct switchdev_obj_port_vlan *vlan)
1493{
Florian Fainellif4589952016-08-26 12:18:33 -07001494 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -07001495 bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
1496 s8 cpu_port = ds->dst->cpu_port;
1497 struct bcm_sf2_vlan *vl;
1498 u16 vid, pvid;
1499 int ret;
1500
1501 pvid = core_readl(priv, CORE_DEFAULT_1Q_TAG_P(port));
1502
1503 for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) {
1504 vl = &priv->vlans[vid];
1505
1506 ret = bcm_sf2_get_vlan_entry(priv, vid, vl);
1507 if (ret)
1508 return ret;
1509
1510 vl->members &= ~BIT(port);
1511 if ((vl->members & BIT(cpu_port)) == BIT(cpu_port))
1512 vl->members = 0;
1513 if (pvid == vid)
1514 pvid = 0;
1515 if (untagged) {
1516 vl->untag &= ~BIT(port);
1517 if ((vl->untag & BIT(port)) == BIT(cpu_port))
1518 vl->untag = 0;
1519 }
1520
1521 bcm_sf2_set_vlan_entry(priv, vid, vl);
1522 bcm_sf2_sw_fast_age_vlan(priv, vid);
1523 }
1524
1525 core_writel(priv, pvid, CORE_DEFAULT_1Q_TAG_P(port));
1526 core_writel(priv, pvid, CORE_DEFAULT_1Q_TAG_P(cpu_port));
1527 bcm_sf2_sw_fast_age_vlan(priv, vid);
1528
1529 return 0;
1530}
1531
1532static int bcm_sf2_sw_vlan_dump(struct dsa_switch *ds, int port,
1533 struct switchdev_obj_port_vlan *vlan,
1534 int (*cb)(struct switchdev_obj *obj))
1535{
Florian Fainellif4589952016-08-26 12:18:33 -07001536 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli9c57a772016-06-09 17:42:08 -07001537 struct bcm_sf2_port_status *p = &priv->port_sts[port];
1538 struct bcm_sf2_vlan *vl;
1539 u16 vid, pvid;
1540 int err = 0;
1541
1542 pvid = core_readl(priv, CORE_DEFAULT_1Q_TAG_P(port));
1543
1544 for (vid = 0; vid < VLAN_N_VID; vid++) {
1545 vl = &priv->vlans[vid];
1546
1547 if (!(vl->members & BIT(port)))
1548 continue;
1549
1550 vlan->vid_begin = vlan->vid_end = vid;
1551 vlan->flags = 0;
1552
1553 if (vl->untag & BIT(port))
1554 vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
1555 if (p->pvid == vid)
1556 vlan->flags |= BRIDGE_VLAN_INFO_PVID;
1557
1558 err = cb(&vlan->obj);
1559 if (err)
1560 break;
1561 }
1562
1563 return err;
1564}
1565
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001566static int bcm_sf2_sw_setup(struct dsa_switch *ds)
1567{
Florian Fainellif4589952016-08-26 12:18:33 -07001568 struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001569 unsigned int port;
Florian Fainellid9338022016-08-18 15:30:14 -07001570
1571 /* Enable all valid ports and disable those unused */
1572 for (port = 0; port < priv->hw_params.num_ports; port++) {
1573 /* IMP port receives special treatment */
1574 if ((1 << port) & ds->enabled_port_mask)
1575 bcm_sf2_port_setup(ds, port, NULL);
1576 else if (dsa_is_cpu_port(ds, port))
1577 bcm_sf2_imp_setup(ds, port);
1578 else
1579 bcm_sf2_port_disable(ds, port, NULL);
1580 }
1581
1582 bcm_sf2_sw_configure_vlan(ds);
1583
1584 return 0;
1585}
1586
Vivien Didelot9d490b42016-08-23 12:38:56 -04001587static struct dsa_switch_ops bcm_sf2_switch_ops = {
Florian Fainellid9338022016-08-18 15:30:14 -07001588 .setup = bcm_sf2_sw_setup,
Andrew Lunn7b314362016-08-22 16:01:01 +02001589 .get_tag_protocol = bcm_sf2_sw_get_tag_protocol,
Florian Fainellid9338022016-08-18 15:30:14 -07001590 .set_addr = bcm_sf2_sw_set_addr,
1591 .get_phy_flags = bcm_sf2_sw_get_phy_flags,
1592 .get_strings = bcm_sf2_sw_get_strings,
1593 .get_ethtool_stats = bcm_sf2_sw_get_ethtool_stats,
1594 .get_sset_count = bcm_sf2_sw_get_sset_count,
1595 .adjust_link = bcm_sf2_sw_adjust_link,
1596 .fixed_link_update = bcm_sf2_sw_fixed_link_update,
1597 .suspend = bcm_sf2_sw_suspend,
1598 .resume = bcm_sf2_sw_resume,
1599 .get_wol = bcm_sf2_sw_get_wol,
1600 .set_wol = bcm_sf2_sw_set_wol,
1601 .port_enable = bcm_sf2_port_setup,
1602 .port_disable = bcm_sf2_port_disable,
1603 .get_eee = bcm_sf2_sw_get_eee,
1604 .set_eee = bcm_sf2_sw_set_eee,
1605 .port_bridge_join = bcm_sf2_sw_br_join,
1606 .port_bridge_leave = bcm_sf2_sw_br_leave,
1607 .port_stp_state_set = bcm_sf2_sw_br_set_stp_state,
1608 .port_fdb_prepare = bcm_sf2_sw_fdb_prepare,
1609 .port_fdb_add = bcm_sf2_sw_fdb_add,
1610 .port_fdb_del = bcm_sf2_sw_fdb_del,
1611 .port_fdb_dump = bcm_sf2_sw_fdb_dump,
1612 .port_vlan_filtering = bcm_sf2_sw_vlan_filtering,
1613 .port_vlan_prepare = bcm_sf2_sw_vlan_prepare,
1614 .port_vlan_add = bcm_sf2_sw_vlan_add,
1615 .port_vlan_del = bcm_sf2_sw_vlan_del,
1616 .port_vlan_dump = bcm_sf2_sw_vlan_dump,
1617};
1618
Florian Fainellif4589952016-08-26 12:18:33 -07001619/* The SWITCH_CORE register space is managed by b53 but operates on a page +
1620 * register basis so we need to translate that into an address that the
1621 * bus-glue understands.
1622 */
1623#define SF2_PAGE_REG_MKADDR(page, reg) ((page) << 10 | (reg) << 2)
1624
1625static int bcm_sf2_core_read8(struct b53_device *dev, u8 page, u8 reg,
1626 u8 *val)
1627{
1628 struct bcm_sf2_priv *priv = dev->priv;
1629
1630 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));
1631
1632 return 0;
1633}
1634
1635static int bcm_sf2_core_read16(struct b53_device *dev, u8 page, u8 reg,
1636 u16 *val)
1637{
1638 struct bcm_sf2_priv *priv = dev->priv;
1639
1640 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));
1641
1642 return 0;
1643}
1644
1645static int bcm_sf2_core_read32(struct b53_device *dev, u8 page, u8 reg,
1646 u32 *val)
1647{
1648 struct bcm_sf2_priv *priv = dev->priv;
1649
1650 *val = core_readl(priv, SF2_PAGE_REG_MKADDR(page, reg));
1651
1652 return 0;
1653}
1654
1655static int bcm_sf2_core_read64(struct b53_device *dev, u8 page, u8 reg,
1656 u64 *val)
1657{
1658 struct bcm_sf2_priv *priv = dev->priv;
1659
1660 *val = core_readq(priv, SF2_PAGE_REG_MKADDR(page, reg));
1661
1662 return 0;
1663}
1664
1665static int bcm_sf2_core_write8(struct b53_device *dev, u8 page, u8 reg,
1666 u8 value)
1667{
1668 struct bcm_sf2_priv *priv = dev->priv;
1669
1670 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));
1671
1672 return 0;
1673}
1674
1675static int bcm_sf2_core_write16(struct b53_device *dev, u8 page, u8 reg,
1676 u16 value)
1677{
1678 struct bcm_sf2_priv *priv = dev->priv;
1679
1680 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));
1681
1682 return 0;
1683}
1684
1685static int bcm_sf2_core_write32(struct b53_device *dev, u8 page, u8 reg,
1686 u32 value)
1687{
1688 struct bcm_sf2_priv *priv = dev->priv;
1689
1690 core_writel(priv, value, SF2_PAGE_REG_MKADDR(page, reg));
1691
1692 return 0;
1693}
1694
1695static int bcm_sf2_core_write64(struct b53_device *dev, u8 page, u8 reg,
1696 u64 value)
1697{
1698 struct bcm_sf2_priv *priv = dev->priv;
1699
1700 core_writeq(priv, value, SF2_PAGE_REG_MKADDR(page, reg));
1701
1702 return 0;
1703}
1704
1705struct b53_io_ops bcm_sf2_io_ops = {
1706 .read8 = bcm_sf2_core_read8,
1707 .read16 = bcm_sf2_core_read16,
1708 .read32 = bcm_sf2_core_read32,
1709 .read48 = bcm_sf2_core_read64,
1710 .read64 = bcm_sf2_core_read64,
1711 .write8 = bcm_sf2_core_write8,
1712 .write16 = bcm_sf2_core_write16,
1713 .write32 = bcm_sf2_core_write32,
1714 .write48 = bcm_sf2_core_write64,
1715 .write64 = bcm_sf2_core_write64,
1716};
1717
Florian Fainellid9338022016-08-18 15:30:14 -07001718static int bcm_sf2_sw_probe(struct platform_device *pdev)
1719{
1720 const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
1721 struct device_node *dn = pdev->dev.of_node;
Florian Fainellif4589952016-08-26 12:18:33 -07001722 struct b53_platform_data *pdata;
Florian Fainellid9338022016-08-18 15:30:14 -07001723 struct bcm_sf2_priv *priv;
Florian Fainellif4589952016-08-26 12:18:33 -07001724 struct b53_device *dev;
Florian Fainellid9338022016-08-18 15:30:14 -07001725 struct dsa_switch *ds;
1726 void __iomem **base;
Florian Fainelli4bd11672016-08-18 15:30:15 -07001727 struct resource *r;
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001728 unsigned int i;
1729 u32 reg, rev;
1730 int ret;
1731
Florian Fainellif4589952016-08-26 12:18:33 -07001732 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1733 if (!priv)
Florian Fainellid9338022016-08-18 15:30:14 -07001734 return -ENOMEM;
1735
Florian Fainellif4589952016-08-26 12:18:33 -07001736 dev = b53_switch_alloc(&pdev->dev, &bcm_sf2_io_ops, priv);
1737 if (!dev)
1738 return -ENOMEM;
Florian Fainellid9338022016-08-18 15:30:14 -07001739
Florian Fainellif4589952016-08-26 12:18:33 -07001740 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
1741 if (!pdata)
1742 return -ENOMEM;
1743
1744 /* Auto-detection using standard registers will not work, so
1745 * provide an indication of what kind of device we are for
1746 * b53_common to work with
1747 */
1748 pdata->chip_id = BCM7445_DEVICE_ID;
1749 dev->pdata = pdata;
1750
1751 priv->dev = dev;
1752 ds = dev->ds;
1753
1754 /* Override the parts that are non-standard wrt. normal b53 devices */
1755 ds->ops->get_tag_protocol = bcm_sf2_sw_get_tag_protocol;
1756 ds->ops->setup = bcm_sf2_sw_setup;
1757 ds->ops->get_phy_flags = bcm_sf2_sw_get_phy_flags;
1758 ds->ops->adjust_link = bcm_sf2_sw_adjust_link;
1759 ds->ops->fixed_link_update = bcm_sf2_sw_fixed_link_update;
1760 ds->ops->suspend = bcm_sf2_sw_suspend;
1761 ds->ops->resume = bcm_sf2_sw_resume;
1762 ds->ops->get_wol = bcm_sf2_sw_get_wol;
1763 ds->ops->set_wol = bcm_sf2_sw_set_wol;
1764 ds->ops->port_enable = bcm_sf2_port_setup;
1765 ds->ops->port_disable = bcm_sf2_port_disable;
1766 ds->ops->get_eee = bcm_sf2_sw_get_eee;
1767 ds->ops->set_eee = bcm_sf2_sw_set_eee;
1768
1769 /* Avoid having DSA free our slave MDIO bus (checking for
1770 * ds->slave_mii_bus and ds->ops->phy_read being non-NULL)
1771 */
1772 ds->ops->phy_read = NULL;
1773
1774 dev_set_drvdata(&pdev->dev, priv);
Florian Fainellid9338022016-08-18 15:30:14 -07001775
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001776 spin_lock_init(&priv->indir_lock);
1777 mutex_init(&priv->stats_mutex);
1778
Florian Fainellid9338022016-08-18 15:30:14 -07001779 bcm_sf2_identify_ports(priv, dn->child);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001780
1781 priv->irq0 = irq_of_parse_and_map(dn, 0);
1782 priv->irq1 = irq_of_parse_and_map(dn, 1);
1783
1784 base = &priv->core;
1785 for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
Florian Fainelli4bd11672016-08-18 15:30:15 -07001786 r = platform_get_resource(pdev, IORESOURCE_MEM, i);
1787 *base = devm_ioremap_resource(&pdev->dev, r);
1788 if (IS_ERR(*base)) {
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001789 pr_err("unable to find register: %s\n", reg_names[i]);
Florian Fainelli4bd11672016-08-18 15:30:15 -07001790 return PTR_ERR(*base);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001791 }
1792 base++;
1793 }
1794
1795 ret = bcm_sf2_sw_rst(priv);
1796 if (ret) {
1797 pr_err("unable to software reset switch: %d\n", ret);
Florian Fainelli4bd11672016-08-18 15:30:15 -07001798 return ret;
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001799 }
1800
1801 ret = bcm_sf2_mdio_register(ds);
1802 if (ret) {
1803 pr_err("failed to register MDIO bus\n");
Florian Fainelli4bd11672016-08-18 15:30:15 -07001804 return ret;
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001805 }
1806
1807 /* Disable all interrupts and request them */
1808 bcm_sf2_intr_disable(priv);
1809
Florian Fainelli4bd11672016-08-18 15:30:15 -07001810 ret = devm_request_irq(&pdev->dev, priv->irq0, bcm_sf2_switch_0_isr, 0,
1811 "switch_0", priv);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001812 if (ret < 0) {
1813 pr_err("failed to request switch_0 IRQ\n");
Florian Fainellibb9c0fa2016-07-29 12:35:57 -07001814 goto out_mdio;
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001815 }
1816
Florian Fainelli4bd11672016-08-18 15:30:15 -07001817 ret = devm_request_irq(&pdev->dev, priv->irq1, bcm_sf2_switch_1_isr, 0,
1818 "switch_1", priv);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001819 if (ret < 0) {
1820 pr_err("failed to request switch_1 IRQ\n");
Florian Fainelli4bd11672016-08-18 15:30:15 -07001821 goto out_mdio;
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001822 }
1823
1824 /* Reset the MIB counters */
1825 reg = core_readl(priv, CORE_GMNCFGCFG);
1826 reg |= RST_MIB_CNT;
1827 core_writel(priv, reg, CORE_GMNCFGCFG);
1828 reg &= ~RST_MIB_CNT;
1829 core_writel(priv, reg, CORE_GMNCFGCFG);
1830
1831 /* Get the maximum number of ports for this switch */
1832 priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
1833 if (priv->hw_params.num_ports > DSA_MAX_PORTS)
1834 priv->hw_params.num_ports = DSA_MAX_PORTS;
1835
1836 /* Assume a single GPHY setup if we can't read that property */
1837 if (of_property_read_u32(dn, "brcm,num-gphy",
1838 &priv->hw_params.num_gphy))
1839 priv->hw_params.num_gphy = 1;
1840
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001841 rev = reg_readl(priv, REG_SWITCH_REVISION);
1842 priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
1843 SWITCH_TOP_REV_MASK;
1844 priv->hw_params.core_rev = (rev & SF2_REV_MASK);
1845
1846 rev = reg_readl(priv, REG_PHY_REVISION);
1847 priv->hw_params.gphy_rev = rev & PHY_REVISION_MASK;
1848
Florian Fainellif4589952016-08-26 12:18:33 -07001849 ret = b53_switch_register(dev);
Florian Fainellid9338022016-08-18 15:30:14 -07001850 if (ret)
Florian Fainelli4bd11672016-08-18 15:30:15 -07001851 goto out_mdio;
Florian Fainellid9338022016-08-18 15:30:14 -07001852
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001853 pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
1854 priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
1855 priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
1856 priv->core, priv->irq0, priv->irq1);
1857
1858 return 0;
1859
Florian Fainellibb9c0fa2016-07-29 12:35:57 -07001860out_mdio:
1861 bcm_sf2_mdio_unregister(priv);
Florian Fainelli7fbb1a92016-06-09 17:42:06 -07001862 return ret;
1863}
1864
Florian Fainellid9338022016-08-18 15:30:14 -07001865static int bcm_sf2_sw_remove(struct platform_device *pdev)
Florian Fainelli246d7f72014-08-27 17:04:56 -07001866{
Florian Fainellif4589952016-08-26 12:18:33 -07001867 struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
Florian Fainellid9338022016-08-18 15:30:14 -07001868
1869 /* Disable all ports and interrupts */
1870 priv->wol_ports_mask = 0;
Florian Fainellif4589952016-08-26 12:18:33 -07001871 bcm_sf2_sw_suspend(priv->dev->ds);
1872 dsa_unregister_switch(priv->dev->ds);
Florian Fainellid9338022016-08-18 15:30:14 -07001873 bcm_sf2_mdio_unregister(priv);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001874
1875 return 0;
1876}
Florian Fainelli246d7f72014-08-27 17:04:56 -07001877
Florian Fainellid9338022016-08-18 15:30:14 -07001878#ifdef CONFIG_PM_SLEEP
1879static int bcm_sf2_suspend(struct device *dev)
Florian Fainelli246d7f72014-08-27 17:04:56 -07001880{
Florian Fainellid9338022016-08-18 15:30:14 -07001881 struct platform_device *pdev = to_platform_device(dev);
Florian Fainellif4589952016-08-26 12:18:33 -07001882 struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
Florian Fainellid9338022016-08-18 15:30:14 -07001883
Florian Fainellif4589952016-08-26 12:18:33 -07001884 return dsa_switch_suspend(priv->dev->ds);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001885}
Florian Fainellid9338022016-08-18 15:30:14 -07001886
1887static int bcm_sf2_resume(struct device *dev)
1888{
1889 struct platform_device *pdev = to_platform_device(dev);
Florian Fainellif4589952016-08-26 12:18:33 -07001890 struct bcm_sf2_priv *priv = platform_get_drvdata(pdev);
Florian Fainellid9338022016-08-18 15:30:14 -07001891
Florian Fainellif4589952016-08-26 12:18:33 -07001892 return dsa_switch_resume(priv->dev->ds);
Florian Fainellid9338022016-08-18 15:30:14 -07001893}
1894#endif /* CONFIG_PM_SLEEP */
1895
1896static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
1897 bcm_sf2_suspend, bcm_sf2_resume);
1898
1899static const struct of_device_id bcm_sf2_of_match[] = {
1900 { .compatible = "brcm,bcm7445-switch-v4.0" },
1901 { /* sentinel */ },
1902};
1903
1904static struct platform_driver bcm_sf2_driver = {
1905 .probe = bcm_sf2_sw_probe,
1906 .remove = bcm_sf2_sw_remove,
1907 .driver = {
1908 .name = "brcm-sf2",
1909 .of_match_table = bcm_sf2_of_match,
1910 .pm = &bcm_sf2_pm_ops,
1911 },
1912};
1913module_platform_driver(bcm_sf2_driver);
Florian Fainelli246d7f72014-08-27 17:04:56 -07001914
1915MODULE_AUTHOR("Broadcom Corporation");
1916MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
1917MODULE_LICENSE("GPL");
1918MODULE_ALIAS("platform:brcm-sf2");