blob: 59e0fabbd97954e250acbf0aefd20d09fa048395 [file] [log] [blame]
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +02001/*
2 * Copyright 2014 Freescale Semiconductor, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 *
6 * Driver for the Vitesse VSC9953 L2 Switch
7 */
8
9#include <asm/io.h>
10#include <asm/fsl_serdes.h>
11#include <fm_eth.h>
Shaohui Xie835c72b2015-03-20 19:28:19 -070012#include <fsl_memac.h>
Codrin Ciubotariu43db9702015-07-24 16:55:26 +030013#include <bitfield.h>
Codrin Ciubotariue111c322015-07-24 16:52:45 +030014#include <errno.h>
15#include <malloc.h>
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020016#include <vsc9953.h>
17
18static struct vsc9953_info vsc9953_l2sw = {
19 .port[0] = VSC9953_PORT_INFO_INITIALIZER(0),
20 .port[1] = VSC9953_PORT_INFO_INITIALIZER(1),
21 .port[2] = VSC9953_PORT_INFO_INITIALIZER(2),
22 .port[3] = VSC9953_PORT_INFO_INITIALIZER(3),
23 .port[4] = VSC9953_PORT_INFO_INITIALIZER(4),
24 .port[5] = VSC9953_PORT_INFO_INITIALIZER(5),
25 .port[6] = VSC9953_PORT_INFO_INITIALIZER(6),
26 .port[7] = VSC9953_PORT_INFO_INITIALIZER(7),
27 .port[8] = VSC9953_PORT_INFO_INITIALIZER(8),
28 .port[9] = VSC9953_PORT_INFO_INITIALIZER(9),
29};
30
Codrin Ciubotariue111c322015-07-24 16:52:45 +030031void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020032{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030033 if (!VSC9953_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020034 return;
35
Codrin Ciubotariue111c322015-07-24 16:52:45 +030036 vsc9953_l2sw.port[port_no].bus = bus;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020037}
38
Codrin Ciubotariue111c322015-07-24 16:52:45 +030039void vsc9953_port_info_set_phy_address(int port_no, int address)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020040{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030041 if (!VSC9953_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020042 return;
43
Codrin Ciubotariue111c322015-07-24 16:52:45 +030044 vsc9953_l2sw.port[port_no].phyaddr = address;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020045}
46
Codrin Ciubotariue111c322015-07-24 16:52:45 +030047void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020048{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030049 if (!VSC9953_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020050 return;
51
Codrin Ciubotariue111c322015-07-24 16:52:45 +030052 vsc9953_l2sw.port[port_no].enet_if = phy_int;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020053}
54
Codrin Ciubotariue111c322015-07-24 16:52:45 +030055void vsc9953_port_enable(int port_no)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020056{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030057 if (!VSC9953_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020058 return;
59
Codrin Ciubotariue111c322015-07-24 16:52:45 +030060 vsc9953_l2sw.port[port_no].enabled = 1;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020061}
62
Codrin Ciubotariue111c322015-07-24 16:52:45 +030063void vsc9953_port_disable(int port_no)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020064{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030065 if (!VSC9953_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020066 return;
67
Codrin Ciubotariue111c322015-07-24 16:52:45 +030068 vsc9953_l2sw.port[port_no].enabled = 0;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020069}
70
71static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr,
72 int regnum, int value)
73{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030074 int timeout = 50000;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020075
76 out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
77 ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
78 (0x1 << 1));
79 asm("sync");
80
81 while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
82 udelay(1);
83
84 if (timeout == 0)
85 debug("Timeout waiting for MDIO write\n");
86}
87
88static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr,
89 int regnum)
90{
Codrin Ciubotariue111c322015-07-24 16:52:45 +030091 int value = 0xFFFF;
92 int timeout = 50000;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +020093
94 while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout)
95 udelay(1);
96 if (timeout == 0) {
97 debug("Timeout waiting for MDIO operation to finish\n");
98 return value;
99 }
100
101 /* Put the address of the phy, and the register
102 * number into MIICMD
103 */
104 out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) |
105 ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) |
106 (0x2 << 1));
107
108 timeout = 50000;
109 /* Wait for the the indication that the read is done */
110 while ((in_le32(&phyregs->miimstatus) & 0x8) && --timeout)
111 udelay(1);
112 if (timeout == 0)
113 debug("Timeout waiting for MDIO read\n");
114
115 /* Grab the value read from the PHY */
116 value = in_le32(&phyregs->miimdata);
117
118 if ((value & 0x00030000) == 0)
119 return value & 0x0000ffff;
120
121 return value;
122}
123
124static int init_phy(struct eth_device *dev)
125{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300126 struct vsc9953_port_info *l2sw_port = dev->priv;
127 struct phy_device *phydev = NULL;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200128
129#ifdef CONFIG_PHYLIB
130 if (!l2sw_port->bus)
131 return 0;
132 phydev = phy_connect(l2sw_port->bus, l2sw_port->phyaddr, dev,
133 l2sw_port->enet_if);
134 if (!phydev) {
135 printf("Failed to connect\n");
136 return -1;
137 }
138
139 phydev->supported &= SUPPORTED_10baseT_Half |
140 SUPPORTED_10baseT_Full |
141 SUPPORTED_100baseT_Half |
142 SUPPORTED_100baseT_Full |
143 SUPPORTED_1000baseT_Full;
144 phydev->advertising = phydev->supported;
145
146 l2sw_port->phydev = phydev;
147
148 phy_config(phydev);
149#endif
150
151 return 0;
152}
153
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300154static int vsc9953_port_init(int port_no)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200155{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300156 struct eth_device *dev;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200157
158 /* Internal ports never have a PHY */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300159 if (VSC9953_INTERNAL_PORT_CHECK(port_no))
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200160 return 0;
161
162 /* alloc eth device */
163 dev = (struct eth_device *)calloc(1, sizeof(struct eth_device));
164 if (!dev)
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300165 return -ENOMEM;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200166
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300167 sprintf(dev->name, "SW@PORT%d", port_no);
168 dev->priv = &vsc9953_l2sw.port[port_no];
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200169 dev->init = NULL;
170 dev->halt = NULL;
171 dev->send = NULL;
172 dev->recv = NULL;
173
174 if (init_phy(dev)) {
175 free(dev);
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300176 return -ENODEV;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200177 }
178
179 return 0;
180}
181
Codrin Ciubotariu43db9702015-07-24 16:55:26 +0300182static int vsc9953_vlan_table_poll_idle(void)
183{
184 struct vsc9953_analyzer *l2ana_reg;
185 int timeout;
186
187 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
188 VSC9953_ANA_OFFSET);
189
190 timeout = 50000;
191 while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
192 VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
193 udelay(1);
194
195 return timeout ? 0 : -EBUSY;
196}
197
198/* vlan table set/clear all membership of vid */
199static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
200{
201 uint val;
202 struct vsc9953_analyzer *l2ana_reg;
203
204 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
205 VSC9953_ANA_OFFSET);
206
207 if (vsc9953_vlan_table_poll_idle() < 0) {
208 debug("VLAN table timeout\n");
209 return;
210 }
211
212 /* read current vlan configuration */
213 val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
214 out_le32(&l2ana_reg->ana_tables.vlan_tidx,
215 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
216
217 clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
218 VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
219
220 if (vsc9953_vlan_table_poll_idle() < 0) {
221 debug("VLAN table timeout\n");
222 return;
223 }
224
225 val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
226 out_le32(&l2ana_reg->ana_tables.vlan_tidx,
227 bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
228
229 clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
230 VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
231 VSC9953_VLAN_CMD_WRITE |
232 (set_member ? VSC9953_VLAN_PORT_MASK : 0));
233}
234
235/* Set PVID for a VSC9953 port */
236static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
237{
238 uint val;
239 struct vsc9953_analyzer *l2ana_reg;
240 struct vsc9953_rew_reg *l2rew_reg;
241
242 /* Administrative down */
243 if (!vsc9953_l2sw.port[port_no].enabled) {
244 printf("Port %d is administrative down\n", port_no);
245 return;
246 }
247
248 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
249 VSC9953_ANA_OFFSET);
250 l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
251 VSC9953_REW_OFFSET);
252
253 /* Set PVID on ingress */
254 val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
255 val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
256 out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
257
258 /* Set PVID on egress */
259 val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
260 val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
261 pvid);
262 out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
263}
264
265static void vsc9953_port_all_vlan_pvid_set(int pvid)
266{
267 int i;
268
269 for (i = 0; i < VSC9953_MAX_PORTS; i++)
270 vsc9953_port_vlan_pvid_set(i, pvid);
271}
272
273/* Enable/disable vlan aware of a VSC9953 port */
274static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
275{
276 struct vsc9953_analyzer *l2ana_reg;
277
278 /* Administrative down */
279 if (!vsc9953_l2sw.port[port_no].enabled) {
280 printf("Port %d is administrative down\n", port_no);
281 return;
282 }
283
284 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
285 VSC9953_ANA_OFFSET);
286
287 if (enabled)
288 setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
289 VSC9953_VLAN_CFG_AWARE_ENA);
290 else
291 clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
292 VSC9953_VLAN_CFG_AWARE_ENA);
293}
294
295/* Set all VSC9953 ports' vlan aware */
296static void vsc9953_port_all_vlan_aware_set(int enabled)
297{
298 int i;
299
300 for (i = 0; i < VSC9953_MAX_PORTS; i++)
301 vsc9953_port_vlan_aware_set(i, enabled);
302}
303
304/* Enable/disable vlan pop count of a VSC9953 port */
305static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
306{
307 uint val;
308 struct vsc9953_analyzer *l2ana_reg;
309
310 /* Administrative down */
311 if (!vsc9953_l2sw.port[port_no].enabled) {
312 printf("Port %d is administrative down\n", port_no);
313 return;
314 }
315
316 if (popcnt > 3 || popcnt < 0) {
317 printf("Invalid pop count value: %d\n", port_no);
318 return;
319 }
320
321 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
322 VSC9953_ANA_OFFSET);
323
324 val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
325 val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
326 popcnt);
327 out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
328}
329
330/* Set all VSC9953 ports' pop count */
331static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
332{
333 int i;
334
335 for (i = 0; i < VSC9953_MAX_PORTS; i++)
336 vsc9953_port_vlan_popcnt_set(i, popcnt);
337}
338
339/* Enable/disable learning for frames dropped due to ingress filtering */
340static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
341{
342 struct vsc9953_analyzer *l2ana_reg;
343
344 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
345 VSC9953_ANA_OFFSET);
346
347 if (enable)
348 setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
349 else
350 clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
351}
352
353/* Egress untag modes of a VSC9953 port */
354enum egress_untag_mode {
355 EGRESS_UNTAG_ALL = 0,
356 EGRESS_UNTAG_PVID_AND_ZERO,
357 EGRESS_UNTAG_ZERO,
358 EGRESS_UNTAG_NONE,
359};
360
361static void vsc9953_port_vlan_egr_untag_set(int port_no,
362 enum egress_untag_mode mode)
363{
364 struct vsc9953_rew_reg *l2rew_reg;
365
366 /* Administrative down */
367 if (!vsc9953_l2sw.port[port_no].enabled) {
368 printf("Port %d is administrative down\n", port_no);
369 return;
370 }
371
372 l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
373 VSC9953_REW_OFFSET);
374
375 switch (mode) {
376 case EGRESS_UNTAG_ALL:
377 clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
378 VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
379 break;
380 case EGRESS_UNTAG_PVID_AND_ZERO:
381 clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
382 VSC9953_TAG_CFG_MASK,
383 VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
384 break;
385 case EGRESS_UNTAG_ZERO:
386 clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
387 VSC9953_TAG_CFG_MASK,
388 VSC9953_TAG_CFG_ALL_BUT_ZERO);
389 break;
390 case EGRESS_UNTAG_NONE:
391 clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
392 VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
393 break;
394 default:
395 printf("Unknown untag mode for port %d\n", port_no);
396 }
397}
398
399static void vsc9953_port_all_vlan_egress_untagged_set(
400 enum egress_untag_mode mode)
401{
402 int i;
403
404 for (i = 0; i < VSC9953_MAX_PORTS; i++)
405 vsc9953_port_vlan_egr_untag_set(i, mode);
406}
407
408/*****************************************************************************
409At startup, the default configuration would be:
410 - HW learning enabled on all ports; (HW default)
411 - All ports are in VLAN 1;
412 - All ports are VLAN aware;
413 - All ports have POP_COUNT 1;
414 - All ports have PVID 1;
415 - All ports have TPID 0x8100; (HW default)
416 - All ports tag frames classified to all VLANs that are not PVID;
417*****************************************************************************/
418void vsc9953_default_configuration(void)
419{
420 int i;
421
422 for (i = 0; i < VSC9953_MAX_VLAN; i++)
423 vsc9953_vlan_table_membership_all_set(i, 0);
424 vsc9953_port_all_vlan_aware_set(1);
425 vsc9953_port_all_vlan_pvid_set(1);
426 vsc9953_port_all_vlan_poncnt_set(1);
427 vsc9953_vlan_table_membership_all_set(1, 1);
428 vsc9953_vlan_ingr_fltr_learn_drop(1);
429 vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
430}
431
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200432void vsc9953_init(bd_t *bis)
433{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300434 u32 i;
435 u32 hdx_cfg = 0;
436 u32 phy_addr = 0;
437 int timeout;
438 struct vsc9953_system_reg *l2sys_reg;
439 struct vsc9953_qsys_reg *l2qsys_reg;
440 struct vsc9953_dev_gmii *l2dev_gmii_reg;
441 struct vsc9953_analyzer *l2ana_reg;
442 struct vsc9953_devcpu_gcb *l2dev_gcb;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200443
444 l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET +
445 VSC9953_DEV_GMII_OFFSET);
446
447 l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
448 VSC9953_ANA_OFFSET);
449
450 l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET +
451 VSC9953_SYS_OFFSET);
452
453 l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
454 VSC9953_QSYS_OFFSET);
455
456 l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET +
457 VSC9953_DEVCPU_GCB);
458
459 out_le32(&l2dev_gcb->chip_regs.soft_rst,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300460 VSC9953_SOFT_SWC_RST_ENA);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200461 timeout = 50000;
462 while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) &
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300463 VSC9953_SOFT_SWC_RST_ENA) && --timeout)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200464 udelay(1); /* busy wait for vsc9953 soft reset */
465 if (timeout == 0)
466 debug("Timeout waiting for VSC9953 to reset\n");
467
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300468 out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE |
469 VSC9953_MEM_INIT);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200470
471 timeout = 50000;
472 while ((in_le32(&l2sys_reg->sys.reset_cfg) &
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300473 VSC9953_MEM_INIT) && --timeout)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200474 udelay(1); /* busy wait for vsc9953 memory init */
475 if (timeout == 0)
476 debug("Timeout waiting for VSC9953 memory to initialize\n");
477
478 out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg)
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300479 | VSC9953_CORE_ENABLE));
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200480
481 /* VSC9953 Setting to be done once only */
482 out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00);
483
484 for (i = 0; i < VSC9953_MAX_PORTS; i++) {
485 if (vsc9953_port_init(i))
486 printf("Failed to initialize l2switch port %d\n", i);
487
488 /* Enable VSC9953 GMII Ports Port ID 0 - 7 */
489 if (VSC9953_INTERNAL_PORT_CHECK(i)) {
490 out_le32(&l2ana_reg->pfc[i].pfc_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300491 VSC9953_PFC_FC_QSGMII);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200492 out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300493 VSC9953_MAC_FC_CFG_QSGMII);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200494 } else {
495 out_le32(&l2ana_reg->pfc[i].pfc_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300496 VSC9953_PFC_FC);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200497 out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i],
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300498 VSC9953_MAC_FC_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200499 }
500 out_le32(&l2dev_gmii_reg->port_mode.clock_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300501 VSC9953_CLOCK_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200502 out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300503 VSC9953_MAC_ENA_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200504 out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300505 VSC9953_MAC_MODE_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200506 out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300507 VSC9953_MAC_IFG_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200508 /* mac_hdx_cfg varies with port id*/
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300509 hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200510 out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg);
511 out_le32(&l2sys_reg->sys.front_port_mode[i],
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300512 VSC9953_FRONT_PORT_MODE);
Codrin Ciubotariu9f3c87f2015-07-24 16:52:46 +0300513 setbits_le32(&l2qsys_reg->sys.switch_port_mode[i],
514 VSC9953_PORT_ENA);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200515 out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg,
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300516 VSC9953_MAC_MAX_LEN);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200517 out_le32(&l2sys_reg->pause_cfg.pause_cfg[i],
Codrin Ciubotariu5ab96442015-07-24 16:52:44 +0300518 VSC9953_PAUSE_CFG);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200519 /* WAIT FOR 2 us*/
520 udelay(2);
521
522 l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(
523 (char *)l2dev_gmii_reg
524 + T1040_SWITCH_GMII_DEV_OFFSET);
525
526 /* Initialize Lynx PHY Wrappers */
527 phy_addr = 0;
528 if (vsc9953_l2sw.port[i].enet_if ==
529 PHY_INTERFACE_MODE_QSGMII)
530 phy_addr = (i + 0x4) & 0x1F;
531 else if (vsc9953_l2sw.port[i].enet_if ==
532 PHY_INTERFACE_MODE_SGMII)
533 phy_addr = (i + 1) & 0x1F;
534
535 if (phy_addr) {
536 /* SGMII IF mode + AN enable */
537 vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
538 0x14, PHY_SGMII_IF_MODE_AN |
539 PHY_SGMII_IF_MODE_SGMII);
540 /* Dev ability according to SGMII specification */
541 vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
542 0x4, PHY_SGMII_DEV_ABILITY_SGMII);
543 /* Adjust link timer for SGMII
544 * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40
545 */
546 vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
547 0x13, 0x0003);
548 vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
549 0x12, 0x0d40);
550 /* Restart AN */
551 vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr,
552 0x0, PHY_SGMII_CR_DEF_VAL |
553 PHY_SGMII_CR_RESET_AN);
554
555 timeout = 50000;
556 while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0],
557 phy_addr, 0x01) & 0x0020) && --timeout)
558 udelay(1); /* wait for AN to complete */
559 if (timeout == 0)
560 debug("Timeout waiting for AN to complete\n");
561 }
562 }
563
Codrin Ciubotariu43db9702015-07-24 16:55:26 +0300564 vsc9953_default_configuration();
565
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200566 printf("VSC9953 L2 switch initialized\n");
567 return;
568}
569
570#ifdef CONFIG_VSC9953_CMD
571/* Enable/disable status of a VSC9953 port */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300572static void vsc9953_port_status_set(int port_no, u8 enabled)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200573{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300574 struct vsc9953_qsys_reg *l2qsys_reg;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200575
576 /* Administrative down */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300577 if (!vsc9953_l2sw.port[port_no].enabled)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200578 return;
579
580 l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
581 VSC9953_QSYS_OFFSET);
582
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300583 if (enabled)
584 setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
585 VSC9953_PORT_ENA);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200586 else
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300587 clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no],
588 VSC9953_PORT_ENA);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200589}
590
591/* Set all VSC9953 ports' status */
592static void vsc9953_port_all_status_set(u8 enabled)
593{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300594 int i;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200595
596 for (i = 0; i < VSC9953_MAX_PORTS; i++)
597 vsc9953_port_status_set(i, enabled);
598}
599
600/* Start autonegotiation for a VSC9953 PHY */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300601static void vsc9953_phy_autoneg(int port_no)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200602{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300603 if (!vsc9953_l2sw.port[port_no].phydev)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200604 return;
605
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300606 if (vsc9953_l2sw.port[port_no].phydev->drv->startup(
607 vsc9953_l2sw.port[port_no].phydev))
608 printf("Failed to start PHY for port %d\n", port_no);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200609}
610
611/* Start autonegotiation for all VSC9953 PHYs */
612static void vsc9953_phy_all_autoneg(void)
613{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300614 int i;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200615
616 for (i = 0; i < VSC9953_MAX_PORTS; i++)
617 vsc9953_phy_autoneg(i);
618}
619
620/* Print a VSC9953 port's configuration */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300621static void vsc9953_port_config_show(int port_no)
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200622{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300623 int speed;
624 int duplex;
625 int link;
626 u8 enabled;
627 u32 val;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200628 struct vsc9953_qsys_reg *l2qsys_reg;
629
630 l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET +
631 VSC9953_QSYS_OFFSET);
632
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300633 val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]);
634 enabled = vsc9953_l2sw.port[port_no].enabled &&
635 (val & VSC9953_PORT_ENA);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200636
637 /* internal ports (8 and 9) are fixed */
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300638 if (VSC9953_INTERNAL_PORT_CHECK(port_no)) {
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200639 link = 1;
640 speed = SPEED_2500;
641 duplex = DUPLEX_FULL;
642 } else {
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300643 if (vsc9953_l2sw.port[port_no].phydev) {
644 link = vsc9953_l2sw.port[port_no].phydev->link;
645 speed = vsc9953_l2sw.port[port_no].phydev->speed;
646 duplex = vsc9953_l2sw.port[port_no].phydev->duplex;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200647 } else {
648 link = -1;
649 speed = -1;
650 duplex = -1;
651 }
652 }
653
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300654 printf("%8d ", port_no);
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200655 printf("%8s ", enabled == 1 ? "enabled" : "disabled");
656 printf("%8s ", link == 1 ? "up" : "down");
657
658 switch (speed) {
659 case SPEED_10:
660 printf("%8d ", 10);
661 break;
662 case SPEED_100:
663 printf("%8d ", 100);
664 break;
665 case SPEED_1000:
666 printf("%8d ", 1000);
667 break;
668 case SPEED_2500:
669 printf("%8d ", 2500);
670 break;
671 case SPEED_10000:
672 printf("%8d ", 10000);
673 break;
674 default:
675 printf("%8s ", "-");
676 }
677
678 printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half");
679}
680
681/* Print VSC9953 ports' configuration */
682static void vsc9953_port_all_config_show(void)
683{
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300684 int i;
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200685
686 for (i = 0; i < VSC9953_MAX_PORTS; i++)
687 vsc9953_port_config_show(i);
688}
689
690/* function to interpret commands starting with "ethsw " */
691static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
692{
693 u8 enable;
694 u32 port;
695
696 if (argc < 4)
697 return -1;
698
699 if (strcmp(argv[1], "port"))
700 return -1;
701
702 if (!strcmp(argv[3], "show")) {
703 if (!strcmp(argv[2], "all")) {
704 vsc9953_phy_all_autoneg();
705 printf("%8s %8s %8s %8s %8s\n",
706 "Port", "Status", "Link", "Speed",
707 "Duplex");
708 vsc9953_port_all_config_show();
709 return 0;
710 } else {
711 port = simple_strtoul(argv[2], NULL, 10);
712 if (!VSC9953_PORT_CHECK(port))
713 return -1;
714 vsc9953_phy_autoneg(port);
715 printf("%8s %8s %8s %8s %8s\n",
716 "Port", "Status", "Link", "Speed",
717 "Duplex");
718 vsc9953_port_config_show(port);
719 return 0;
720 }
721 } else if (!strcmp(argv[3], "enable")) {
722 enable = 1;
723 } else if (!strcmp(argv[3], "disable")) {
724 enable = 0;
725 } else {
726 return -1;
727 }
728
729 if (!strcmp(argv[2], "all")) {
730 vsc9953_port_all_status_set(enable);
731 return 0;
732 } else {
733 port = simple_strtoul(argv[2], NULL, 10);
734 if (!VSC9953_PORT_CHECK(port))
735 return -1;
736 vsc9953_port_status_set(port, enable);
737 return 0;
738 }
739
740 return -1;
741}
742
743U_BOOT_CMD(ethsw, 5, 0, do_ethsw,
744 "vsc9953 l2 switch commands",
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300745 "port <port_no> enable|disable\n"
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200746 " - enable/disable an l2 switch port\n"
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300747 " port_no=0..9; use \"all\" for all ports\n"
748 "ethsw port <port_no> show\n"
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200749 " - show an l2 switch port's configuration\n"
Codrin Ciubotariue111c322015-07-24 16:52:45 +0300750 " port_no=0..9; use \"all\" for all ports\n"
Codrin Ciubotariu6abe0782015-01-12 14:08:33 +0200751);
752#endif /* CONFIG_VSC9953_CMD */