[package] update e2fsprogs to 1.41.11 (#6896)
[openwrt.git] / package / broadcom-57xx / src / bcmrobo.c
1 /*
2  * Broadcom BCM5325E/536x switch configuration module
3  *
4  * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * Based on:
17  *   Broadcom 53xx RoboSwitch device driver.
18  *
19  *   Copyright 2007, Broadcom Corporation
20  *   All Rights Reserved.
21  * 
22  *   THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
23  *   KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
24  *   SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25  *   FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
26  */
27
28
29 #include <linux/autoconf.h>
30 #include <linux/module.h>
31 #include <linux/init.h>
32 #include <asm/uaccess.h>
33
34 #include <typedefs.h>
35 #include <osl.h>
36 #include <sbutils.h>
37 #include <sbconfig.h>
38 #include <bcmendian.h>
39 #include "bcmparams.h"
40 #include <bcmnvram.h>
41 #include <bcmdevs.h>
42 #include "bcmrobo.h"
43 #include "proto/ethernet.h"
44 #include <switch-core.h>
45
46 #define DRIVER_NAME             "bcm57xx"
47 #define DRIVER_VERSION  "0.1"
48
49 #ifndef GPIO_PIN_NOTDEFINED
50 #define GPIO_PIN_NOTDEFINED     0x20
51 #endif
52
53 #ifdef  BCMDBG
54 #define ET_ERROR(args)  printk args
55 #else   /* BCMDBG */
56 #define ET_ERROR(args)
57 #endif  /* BCMDBG */
58 #define ET_MSG(args)
59
60 /*
61  * Switch can be programmed through SPI interface, which
62  * has a rreg and a wreg functions to read from and write to
63  * registers.
64  */
65
66 /* MII access registers */
67 #define PSEUDO_PHYAD    0x1E    /* MII Pseudo PHY address */
68 #define REG_MII_PAGE    0x10    /* MII Page register */
69 #define REG_MII_ADDR    0x11    /* MII Address register */
70 #define REG_MII_DATA0   0x18    /* MII Data register 0 */
71 #define REG_MII_DATA1   0x19    /* MII Data register 1 */
72 #define REG_MII_DATA2   0x1a    /* MII Data register 2 */
73 #define REG_MII_DATA3   0x1b    /* MII Data register 3 */
74
75 /* Page numbers */
76 #define PAGE_CTRL       0x00    /* Control page */
77 #define PAGE_MMR        0x02    /* 5397 Management/Mirroring page */
78 #define PAGE_VTBL       0x05    /* ARL/VLAN Table access page */
79 #define PAGE_VLAN       0x34    /* VLAN page */
80
81 /* Control page registers */
82 #define REG_CTRL_PORT0  0x00    /* Port 0 traffic control register */
83 #define REG_CTRL_PORT1  0x01    /* Port 1 traffic control register */
84 #define REG_CTRL_PORT2  0x02    /* Port 2 traffic control register */
85 #define REG_CTRL_PORT3  0x03    /* Port 3 traffic control register */
86 #define REG_CTRL_PORT4  0x04    /* Port 4 traffic control register */
87 #define REG_CTRL_PORT5  0x05    /* Port 5 traffic control register */
88 #define REG_CTRL_PORT6  0x06    /* Port 6 traffic control register */
89 #define REG_CTRL_PORT7  0x07    /* Port 7 traffic control register */
90 #define REG_CTRL_MODE   0x0B    /* Switch Mode register */
91 #define REG_CTRL_MIIPO  0x0E    /* 5325: MII Port Override register */
92 #define REG_CTRL_SRST   0x79    /* Software reset control register */
93
94 #define REG_DEVICE_ID   0x30    /* 539x Device id: */
95 #define DEVID5325       0x25    /*  5325 (Not really be we fake it) */
96 #define DEVID5395       0x95    /*  5395 */
97 #define DEVID5397       0x97    /*  5397 */
98 #define DEVID5398       0x98    /*  5398 */
99 #define DEVID53115      0x3115  /* 53115 */
100
101 /* VLAN page registers */
102 #define REG_VLAN_CTRL0  0x00    /* VLAN Control 0 register */
103 #define REG_VLAN_CTRL1  0x01    /* VLAN Control 1 register */
104 #define REG_VLAN_CTRL4  0x04    /* VLAN Control 4 register */
105 #define REG_VLAN_CTRL5  0x05    /* VLAN Control 5 register */
106 #define REG_VLAN_ACCESS 0x06    /* VLAN Table Access register */
107 #define REG_VLAN_WRITE  0x08    /* VLAN Write register */
108 #define REG_VLAN_READ   0x0C    /* VLAN Read register */
109 #define REG_VLAN_PTAG0  0x10    /* VLAN Default Port Tag register - port 0 */
110 #define REG_VLAN_PTAG1  0x12    /* VLAN Default Port Tag register - port 1 */
111 #define REG_VLAN_PTAG2  0x14    /* VLAN Default Port Tag register - port 2 */
112 #define REG_VLAN_PTAG3  0x16    /* VLAN Default Port Tag register - port 3 */
113 #define REG_VLAN_PTAG4  0x18    /* VLAN Default Port Tag register - port 4 */
114 #define REG_VLAN_PTAG5  0x1a    /* VLAN Default Port Tag register - port 5 */
115 #define REG_VLAN_PTAG6  0x1c    /* VLAN Default Port Tag register - port 6 */
116 #define REG_VLAN_PTAG7  0x1e    /* VLAN Default Port Tag register - port 7 */
117 #define REG_VLAN_PTAG8  0x20    /* 539x: VLAN Default Port Tag register - IMP port */
118 #define REG_VLAN_PMAP   0x20    /* 5325: VLAN Priority Re-map register */
119
120 #define VLAN_NUMVLANS   16      /* # of VLANs */
121
122
123 /* ARL/VLAN Table Access page registers */
124 #define REG_VTBL_CTRL           0x00    /* ARL Read/Write Control */
125 #define REG_VTBL_MINDX          0x02    /* MAC Address Index */
126 #define REG_VTBL_VINDX          0x08    /* VID Table Index */
127 #define REG_VTBL_ARL_E0         0x10    /* ARL Entry 0 */
128 #define REG_VTBL_ARL_E1         0x18    /* ARL Entry 1 */
129 #define REG_VTBL_DAT_E0         0x18    /* ARL Table Data Entry 0 */
130 #define REG_VTBL_SCTRL          0x20    /* ARL Search Control */
131 #define REG_VTBL_SADDR          0x22    /* ARL Search Address */
132 #define REG_VTBL_SRES           0x24    /* ARL Search Result */
133 #define REG_VTBL_SREXT          0x2c    /* ARL Search Result */
134 #define REG_VTBL_VID_E0         0x30    /* VID Entry 0 */
135 #define REG_VTBL_VID_E1         0x32    /* VID Entry 1 */
136 #define REG_VTBL_PREG           0xFF    /* Page Register */
137 #define REG_VTBL_ACCESS         0x60    /* VLAN table access register */
138 #define REG_VTBL_INDX           0x61    /* VLAN table address index register */
139 #define REG_VTBL_ENTRY          0x63    /* VLAN table entry register */
140 #define REG_VTBL_ACCESS_5395    0x80    /* VLAN table access register */
141 #define REG_VTBL_INDX_5395      0x81    /* VLAN table address index register */
142 #define REG_VTBL_ENTRY_5395     0x83    /* VLAN table entry register */
143
144 /* SPI registers */
145 #define REG_SPI_PAGE    0xff    /* SPI Page register */
146
147 /* Access switch registers through GPIO/SPI */
148
149 /* Minimum timing constants */
150 #define SCK_EDGE_TIME   2       /* clock edge duration - 2us */
151 #define MOSI_SETUP_TIME 1       /* input setup duration - 1us */
152 #define SS_SETUP_TIME   1       /* select setup duration - 1us */
153
154 /* misc. constants */
155 #define SPI_MAX_RETRY   100
156
157 static int config_attach(robo_info_t *robo);
158 static void config_detach(robo_info_t *robo);
159
160 /* Enable GPIO access to the chip */
161 static void
162 gpio_enable(robo_info_t *robo)
163 {
164         /* Enable GPIO outputs with SCK and MOSI low, SS high */
165         sb_gpioout(robo->sbh, robo->ss | robo->sck | robo->mosi, robo->ss, GPIO_DRV_PRIORITY);
166         sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi,
167                      robo->ss | robo->sck | robo->mosi, GPIO_DRV_PRIORITY);
168 }
169
170 /* Disable GPIO access to the chip */
171 static void
172 gpio_disable(robo_info_t *robo)
173 {
174         /* Disable GPIO outputs with all their current values */
175         sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi, 0, GPIO_DRV_PRIORITY);
176 }
177
178 /* Write a byte stream to the chip thru SPI */
179 static int
180 spi_write(robo_info_t *robo, uint8 *buf, uint len)
181 {
182         uint i;
183         uint8 mask;
184
185         /* Byte bang from LSB to MSB */
186         for (i = 0; i < len; i++) {
187                 /* Bit bang from MSB to LSB */
188                 for (mask = 0x80; mask; mask >>= 1) {
189                         /* Clock low */
190                         sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY);
191                         OSL_DELAY(SCK_EDGE_TIME);
192
193                         /* Sample on rising edge */
194                         if (mask & buf[i])
195                                 sb_gpioout(robo->sbh, robo->mosi, robo->mosi, GPIO_DRV_PRIORITY);
196                         else
197                                 sb_gpioout(robo->sbh, robo->mosi, 0, GPIO_DRV_PRIORITY);
198                         OSL_DELAY(MOSI_SETUP_TIME);
199
200                         /* Clock high */
201                         sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
202                         OSL_DELAY(SCK_EDGE_TIME);
203                 }
204         }
205
206         return 0;
207 }
208
209 /* Read a byte stream from the chip thru SPI */
210 static int
211 spi_read(robo_info_t *robo, uint8 *buf, uint len)
212 {
213         uint i, timeout;
214         uint8 rack, mask, byte;
215
216         /* Timeout after 100 tries without RACK */
217         for (i = 0, rack = 0, timeout = SPI_MAX_RETRY; i < len && timeout;) {
218                 /* Bit bang from MSB to LSB */
219                 for (mask = 0x80, byte = 0; mask; mask >>= 1) {
220                         /* Clock low */
221                         sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY);
222                         OSL_DELAY(SCK_EDGE_TIME);
223
224                         /* Sample on falling edge */
225                         if (sb_gpioin(robo->sbh) & robo->miso)
226                                 byte |= mask;
227
228                         /* Clock high */
229                         sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY);
230                         OSL_DELAY(SCK_EDGE_TIME);
231                 }
232                 /* RACK when bit 0 is high */
233                 if (!rack) {
234                         rack = (byte & 1);
235                         timeout--;
236                         continue;
237                 }
238                 /* Byte bang from LSB to MSB */
239                 buf[i] = byte;
240                 i++;
241         }
242
243         if (timeout == 0) {
244                 ET_ERROR(("spi_read: timeout"));
245                 return -1;
246         }
247
248         return 0;
249 }
250
251 /* Enable/disable SPI access */
252 static void
253 spi_select(robo_info_t *robo, uint8 spi)
254 {
255         if (spi) {
256                 /* Enable SPI access */
257                 sb_gpioout(robo->sbh, robo->ss, 0, GPIO_DRV_PRIORITY);
258         } else {
259                 /* Disable SPI access */
260                 sb_gpioout(robo->sbh, robo->ss, robo->ss, GPIO_DRV_PRIORITY);
261         }
262         OSL_DELAY(SS_SETUP_TIME);
263 }
264
265
266 /* Select chip and page */
267 static void
268 spi_goto(robo_info_t *robo, uint8 page)
269 {
270         uint8 reg8 = REG_SPI_PAGE;      /* page select register */
271         uint8 cmd8;
272
273         /* Issue the command only when we are on a different page */
274         if (robo->page == page)
275                 return;
276
277         robo->page = page;
278
279         /* Enable SPI access */
280         spi_select(robo, 1);
281
282         /* Select new page with CID 0 */
283         cmd8 = ((6 << 4) |              /* normal SPI */
284                 1);                     /* write */
285         spi_write(robo, &cmd8, 1);
286         spi_write(robo, &reg8, 1);
287         spi_write(robo, &page, 1);
288
289         /* Disable SPI access */
290         spi_select(robo, 0);
291 }
292
293 /* Write register thru SPI */
294 static int
295 spi_wreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
296 {
297         int status = 0;
298         uint8 cmd8;
299         union {
300                 uint8 val8;
301                 uint16 val16;
302                 uint32 val32;
303         } bytes;
304
305         /* validate value length and buffer address */
306         ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
307                (len == 4 && !((int)val & 3)));
308
309         /* Select chip and page */
310         spi_goto(robo, page);
311
312         /* Enable SPI access */
313         spi_select(robo, 1);
314
315         /* Write with CID 0 */
316         cmd8 = ((6 << 4) |              /* normal SPI */
317                 1);                     /* write */
318         spi_write(robo, &cmd8, 1);
319         spi_write(robo, &addr, 1);
320         switch (len) {
321         case 1:
322                 bytes.val8 = *(uint8 *)val;
323                 break;
324         case 2:
325                 bytes.val16 = htol16(*(uint16 *)val);
326                 break;
327         case 4:
328                 bytes.val32 = htol32(*(uint32 *)val);
329                 break;
330         }
331         spi_write(robo, (uint8 *)val, len);
332
333         ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, addr,
334                 *(uint16 *)val, len));
335         /* Disable SPI access */
336         spi_select(robo, 0);
337         return status;
338 }
339
340 /* Read register thru SPI in fast SPI mode */
341 static int
342 spi_rreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len)
343 {
344         int status = 0;
345         uint8 cmd8;
346         union {
347                 uint8 val8;
348                 uint16 val16;
349                 uint32 val32;
350         } bytes;
351
352         /* validate value length and buffer address */
353         ASSERT(len == 1 || (len == 2 && !((int)val & 1)) ||
354                (len == 4 && !((int)val & 3)));
355
356         /* Select chip and page */
357         spi_goto(robo, page);
358
359         /* Enable SPI access */
360         spi_select(robo, 1);
361
362         /* Fast SPI read with CID 0 and byte offset 0 */
363         cmd8 = (1 << 4);                /* fast SPI */
364         spi_write(robo, &cmd8, 1);
365         spi_write(robo, &addr, 1);
366         status = spi_read(robo, (uint8 *)&bytes, len);
367         switch (len) {
368         case 1:
369                 *(uint8 *)val = bytes.val8;
370                 break;
371         case 2:
372                 *(uint16 *)val = ltoh16(bytes.val16);
373                 break;
374         case 4:
375                 *(uint32 *)val = ltoh32(bytes.val32);
376                 break;
377         }
378
379         ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, addr,
380                 *(uint16 *)val, len));
381
382         /* Disable SPI access */
383         spi_select(robo, 0);
384         return status;
385 }
386
387 /* SPI/gpio interface functions */
388 static dev_ops_t spigpio = {
389         gpio_enable,
390         gpio_disable,
391         spi_wreg,
392         spi_rreg,
393         "SPI (GPIO)"
394 };
395
396
397 /* Access switch registers through MII (MDC/MDIO) */
398
399 #define MII_MAX_RETRY   100
400
401 /* Write register thru MDC/MDIO */
402 static  int
403 mii_wreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
404 {
405         uint16 cmd16, val16,val48[3];
406         void *h = robo->h;
407     uint32 val64[2];
408         memset(val48,0,6);
409         memset(val64,0,8);
410         int i;
411         uint8 *ptr = (uint8 *)val;
412
413         /* validate value length and buffer address */
414         ASSERT(len == 1 || len == 6 || len == 8 ||
415                ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
416
417         ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, reg,
418                   *(uint16 *)val, len));
419
420         /* set page number - MII register 0x10 */
421         if (robo->page != page) {
422                 cmd16 = ((page << 8) |          /* page number */
423                          1);                    /* mdc/mdio access enable */
424                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
425                 robo->page = page;
426         }
427
428         switch (len) {
429         case 8:
430                 val16 = ptr[7];
431                 val16 = ((val16 << 8) | ptr[6]);
432                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA3, val16);
433                 /* FALLTHRU */
434
435         case 6:
436                 val16 = ptr[5];
437                 val16 = ((val16 << 8) | ptr[4]);
438                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA2, val16);
439                 val16 = ptr[3];
440                 val16 = ((val16 << 8) | ptr[2]);
441                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
442                 val16 = ptr[1];
443                 val16 = ((val16 << 8) | ptr[0]);
444                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
445                 break;
446
447         case 4:
448                 val16 = (uint16)((*(uint32 *)val) >> 16);
449                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16);
450                 val16 = (uint16)(*(uint32 *)val);
451                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
452                 break;
453
454         case 2:
455                 val16 = *(uint16 *)val;
456                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
457                 break;
458
459         case 1:
460                 val16 = *(uint8 *)val;
461                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16);
462                 break;
463         }
464
465         /* set register address - MII register 0x11 */
466         cmd16 = ((reg << 8) |           /* register address */
467                  1);            /* opcode write */
468         robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
469
470         /* is operation finished? */
471         for (i = MII_MAX_RETRY; i > 0; i --) {
472                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
473                 if ((val16 & 3) == 0)
474                         break;
475         }
476
477         /* timed out */
478         if (!i) {
479                 ET_ERROR(("mii_wreg: timeout"));
480                 return -1;
481         }
482         return 0;
483 }
484
485 /* Read register thru MDC/MDIO */
486 static  int
487 mii_rreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len)
488 {
489         uint16 cmd16, val16;
490         void *h = robo->h;
491         int i;
492         uint8 *ptr = (uint8 *)val;
493
494         /* validate value length and buffer address */
495         ASSERT(len == 1 || len == 6 || len == 8 ||
496                ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3)));
497
498         /* set page number - MII register 0x10 */
499         if (robo->page != page) {
500                 cmd16 = ((page << 8) |          /* page number */
501                          1);                    /* mdc/mdio access enable */
502                 robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16);
503                 robo->page = page;
504         }
505
506         /* set register address - MII register 0x11 */
507         cmd16 = ((reg << 8) |           /* register address */
508                  2);                    /* opcode read */
509         robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16);
510
511         /* is operation finished? */
512         for (i = MII_MAX_RETRY; i > 0; i --) {
513                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR);
514                 if ((val16 & 3) == 0)
515                         break;
516         }
517         /* timed out */
518         if (!i) {
519                 ET_ERROR(("mii_rreg: timeout"));
520                 return -1;
521         }
522
523         ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, reg, val16, len));
524
525         switch (len) {
526         case 8:
527                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA3);
528                 ptr[7] = (val16 >> 8);
529                 ptr[6] = (val16 & 0xff);
530                 /* FALLTHRU */
531
532         case 6:
533                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA2);
534                 ptr[5] = (val16 >> 8);
535                 ptr[4] = (val16 & 0xff);
536                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
537                 ptr[3] = (val16 >> 8);
538                 ptr[2] = (val16 & 0xff);
539                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
540                 ptr[1] = (val16 >> 8);
541                 ptr[0] = (val16 & 0xff);
542                 break;
543
544         case 4:
545                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1);
546                 *(uint32 *)val = (((uint32)val16) << 16);
547                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
548                 *(uint32 *)val |= val16;
549                 break;
550
551         case 2:
552                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
553                 *(uint16 *)val = val16;
554                 break;
555         case 1:
556                 val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0);
557                 *(uint8 *)val = (uint8)(val16 & 0xff);
558                 break;
559         }
560
561         return 0;
562 }
563
564 /* MII interface functions */
565 static dev_ops_t mdcmdio = {
566         NULL,
567         NULL,
568         mii_wreg,
569         mii_rreg,
570         "MII (MDC/MDIO)"
571 };
572
573 /* High level switch configuration functions. */
574
575 static int
576 findmatch(char *string, char *name)
577 {
578         uint len;
579         char *c;
580
581         len = strlen(name);
582         /* CSTYLED */
583         while ((c = strchr(string, ',')) != NULL) {
584                 if (len == (uint)(c - string) && !strncmp(string, name, len))
585                         return 1;
586                 string = c + 1;
587         }
588
589         return (!strcmp(string, name));
590 }
591
592 static uint
593 getgpiopin(char *vars, char *pin_name, uint def_pin)
594 {
595         char name[] = "gpioXXXX";
596         char *val;
597         uint pin;
598
599         /* Go thru all possibilities till a match in pin name */
600         for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
601                 snprintf(name, sizeof(name), "gpio%d", pin);
602                 val = getvar(vars, name);
603                 if (val && findmatch(val, pin_name))
604                         return pin;
605         }
606
607         if (def_pin != GPIO_PIN_NOTDEFINED) {
608                 /* make sure the default pin is not used by someone else */
609                 snprintf(name, sizeof(name), "gpio%d", def_pin);
610                 if (getvar(vars, name)) {
611                         def_pin =  GPIO_PIN_NOTDEFINED;
612                 }
613         }
614
615         return def_pin;
616 }
617
618
619 /* Port flags */
620 #define FLAG_TAGGED     't'     /* output tagged (external ports only) */
621 #define FLAG_UNTAG      'u'     /* input & output untagged (CPU port only, for OS (linux, ...) */
622 #define FLAG_LAN        '*'     /* input & output untagged (CPU port only, for CFE */
623
624 /* port descriptor */
625 typedef struct {
626         uint32 untag;   /* untag enable bit (Page 0x05 Address 0x63-0x66 Bit[17:9]) */
627         uint32 member;  /* vlan member bit (Page 0x05 Address 0x63-0x66 Bit[7:0]) */
628         uint8 ptagr;    /* port tag register address (Page 0x34 Address 0x10-0x1F) */
629         uint8 cpu;      /* is this cpu port? */
630 } pdesc_t;
631
632 pdesc_t pdesc97[] = {
633         /* 5395/5397/5398 is 0 ~ 7.  port 8 is IMP port. */
634         /* port 0 */ {1 << 9, 1 << 0, REG_VLAN_PTAG0, 0},
635         /* port 1 */ {1 << 10, 1 << 1, REG_VLAN_PTAG1, 0},
636         /* port 2 */ {1 << 11, 1 << 2, REG_VLAN_PTAG2, 0},
637         /* port 3 */ {1 << 12, 1 << 3, REG_VLAN_PTAG3, 0},
638         /* port 4 */ {1 << 13, 1 << 4, REG_VLAN_PTAG4, 0},
639         /* port 5 */ {1 << 14, 1 << 5, REG_VLAN_PTAG5, 0},
640         /* port 6 */ {1 << 15, 1 << 6, REG_VLAN_PTAG6, 0},
641         /* port 7 */ {1 << 16, 1 << 7, REG_VLAN_PTAG7, 0},
642         /* mii port */ {1 << 17, 1 << 8, REG_VLAN_PTAG8, 1},
643 };
644
645 pdesc_t pdesc25[] = {
646         /* port 0 */ {1 << 6, 1 << 0, REG_VLAN_PTAG0, 0},
647         /* port 1 */ {1 << 7, 1 << 1, REG_VLAN_PTAG1, 0},
648         /* port 2 */ {1 << 8, 1 << 2, REG_VLAN_PTAG2, 0},
649         /* port 3 */ {1 << 9, 1 << 3, REG_VLAN_PTAG3, 0},
650         /* port 4 */ {1 << 10, 1 << 4, REG_VLAN_PTAG4, 0},
651         /* mii port */ {1 << 11, 1 << 5, REG_VLAN_PTAG5, 1},
652 };
653
654
655 #define to_robo(driver) ((robo_info_t *) ((switch_driver *) driver)->priv)
656 #define ROBO_START(driver) \
657         do { \
658                 robo_info_t *robo = to_robo(driver); \
659                 if (robo->ops->enable_mgmtif) \
660                         robo->ops->enable_mgmtif(robo)
661
662 #define ROBO_END(driver) \
663                 if (robo->ops->disable_mgmtif) \
664                         robo->ops->disable_mgmtif(robo); \
665         } while (0)
666
667 int
668 bcm_robo_reset(robo_info_t *robo)
669 {
670         int i, max_port_ind;
671         uint8 val8;
672         uint16 val16;
673         uint32 val32;
674         pdesc_t *pdesc;
675         int pdescsz;
676
677 /* printk(KERN_WARNING "bcmrobo.c: bcm_robo_reset\n"); */
678
679         if (robo->ops->enable_mgmtif)
680                 robo->ops->enable_mgmtif(robo);
681
682         /* setup global vlan configuration, FIXME: necessary? */
683         /* VLAN Control 0 Register (Page 0x34, Address 0) */
684         val8 = ((1 << 7) |              /* enable 802.1Q VLAN */
685                 (3 << 5));              /* individual VLAN learning mode */
686         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
687
688         /* VLAN Control 1 Register (Page 0x34, Address 1) */
689         robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
690         val8 |= ((1 << 2) |             /* enable RSV multicast V Fwdmap */
691                 (1 << 3));              /* enable RSV multicast V Untagmap */
692         if (robo->devid == DEVID5325)
693                 val8 |= (1 << 1);       /* enable RSV multicast V Tagging */
694         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
695
696         bcm_robo_set_macaddr(robo, NULL);
697
698         if (robo->devid == DEVID5325) {
699                 /* VLAN Control 4 Register (Page 0x34, Address 4) */
700                 val8 = (1 << 6);                /* drop frame with VID violation */
701                 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8));
702
703                 /* VLAN Control 5 Register (Page 0x34, Address 5) */
704                 val8 = (1 << 3);                /* drop frame when miss V table */
705                 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8));
706
707                 pdesc = pdesc25;
708                 pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
709         } else {
710                 pdesc = pdesc97;
711                 pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
712         }
713
714         if (robo->devid == DEVID5325) {
715                 /* setup priority mapping - applies to tagged ingress frames */
716                 /* Priority Re-map Register (Page 0x34, Address 0x20-0x23) */
717                 /* FIXME: un-hardcode */
718                 val32 = ((0 << 0) |     /* 0 -> 0 */
719                          (1 << 3) |     /* 1 -> 1 */
720                          (2 << 6) |     /* 2 -> 2 */
721                          (3 << 9) |     /* 3 -> 3 */
722                          (4 << 12) |    /* 4 -> 4 */
723                          (5 << 15) |    /* 5 -> 5 */
724                          (6 << 18) |    /* 6 -> 6 */
725                          (7 << 21));    /* 7 -> 7 */
726                 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_PMAP, &val32, sizeof(val32));
727         }
728
729         /* Set unmanaged mode */
730         robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
731         val8 &= (~(1 << 0));
732         robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
733
734         /* No spanning tree for unmanaged mode */
735         val8 = 0;
736         max_port_ind = ((robo->devid == DEVID5398) ? REG_CTRL_PORT7 : REG_CTRL_PORT4);
737         for (i = REG_CTRL_PORT0; i <= max_port_ind; i++) {
738                 robo->ops->write_reg(robo, PAGE_CTRL, i, &val8, sizeof(val8));
739         }
740
741         /* WAN port LED */
742         val16 = 0x1f;
743         robo->ops->write_reg(robo, PAGE_CTRL, 0x16, &val16, 2);
744
745         if (robo->ops->enable_mgmtif)
746                 robo->ops->disable_mgmtif(robo);
747
748         return 0;
749 }
750
751 /* Get access to the RoboSwitch */
752 robo_info_t *
753 bcm_robo_attach(sb_t *sbh, void *h, char *name, char *vars, miird_f miird, miiwr_f miiwr)
754 {
755         robo_info_t *robo;
756         uint32 reset, idx;
757         uint8 val8;
758         uint16 val16;
759
760         /* Allocate and init private state */
761         if (!(robo = MALLOC(sb_osh(sbh), sizeof(robo_info_t)))) {
762                 ET_ERROR(("robo_attach: out of memory, malloced %d bytes", MALLOCED(sb_osh(sbh))));
763                 return NULL;
764         }
765         bzero(robo, sizeof(robo_info_t));
766
767         robo->h = h;
768         robo->sbh = sbh;
769         robo->vars = vars;
770         robo->miird = miird;
771         robo->miiwr = miiwr;
772         robo->page = -1;
773         robo->name = name;
774
775         /* Trigger external reset by nvram variable existance */
776         if ((reset = getgpiopin(robo->vars, "robo_reset", GPIO_PIN_NOTDEFINED)) !=
777             GPIO_PIN_NOTDEFINED) {
778                 /*
779                  * Reset sequence: RESET low(50ms)->high(20ms)
780                  *
781                  * We have to perform a full sequence for we don't know how long
782                  * it has been from power on till now.
783                  */
784                 ET_MSG(("%s: Using external reset in gpio pin %d\n", __FUNCTION__, reset));
785                 reset = 1 << reset;
786
787                 /* Keep RESET low for 50 ms */
788                 sb_gpioout(robo->sbh, reset, 0, GPIO_DRV_PRIORITY);
789                 sb_gpioouten(robo->sbh, reset, reset, GPIO_DRV_PRIORITY);
790                 bcm_mdelay(50);
791
792                 /* Keep RESET high for at least 20 ms */
793                 sb_gpioout(robo->sbh, reset, reset, GPIO_DRV_PRIORITY);
794                 bcm_mdelay(20);
795         } else {
796                 /* In case we need it */
797                 idx = sb_coreidx(robo->sbh);
798
799                 if (sb_setcore(robo->sbh, SB_ROBO, 0)) {
800                         /* If we have an internal robo core, reset it using sb_core_reset */
801                         ET_MSG(("%s: Resetting internal robo core\n", __FUNCTION__));
802                         sb_core_reset(robo->sbh, 0, 0);
803                 }
804
805                 sb_setcoreidx(robo->sbh, idx);
806         }
807
808         if (miird && miiwr) {
809                 uint16 tmp;
810                 int rc, retry_count = 0;
811
812                 /* Read the PHY ID */
813                 tmp = miird(h, PSEUDO_PHYAD, 2);
814                 if (tmp != 0xffff) {
815                         do {
816                                 rc = mii_rreg(robo, PAGE_MMR, REG_DEVICE_ID, \
817                                                           &robo->devid, sizeof(uint16));
818                                 if (rc != 0)
819                                         break;
820                                 retry_count++;
821                         } while ((robo->devid == 0) && (retry_count < 10));
822
823                         ET_MSG(("%s: devid read %ssuccesfully via mii: 0x%x\n", __FUNCTION__, \
824                                 rc ? "un" : "", robo->devid));
825                         ET_MSG(("%s: mii access to switch works\n", __FUNCTION__));
826                         robo->ops = &mdcmdio;
827                         if ((rc != 0) || (robo->devid == 0)) {
828                                 ET_MSG(("%s: error reading devid, assuming 5325e\n", __FUNCTION__));
829                                 robo->devid = DEVID5325;
830                         }
831                         ET_MSG(("%s: devid: 0x%x\n", __FUNCTION__, robo->devid));
832                 }
833         }
834
835         if ((robo->devid == DEVID5395) ||
836             (robo->devid == DEVID5397) ||
837             (robo->devid == DEVID5398)) {
838                 uint8 srst_ctrl;
839
840                 /* If it is a 539x switch, use the soft reset register */
841                 ET_MSG(("%s: Resetting 539x robo switch\n", __FUNCTION__));
842
843                 /* Reset the 539x switch core and register file */
844                 srst_ctrl = 0x83;
845                 mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
846
847                 bcm_mdelay(500);
848
849                 srst_ctrl = 0x00;
850                 mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8));
851         }
852
853         if (!robo->ops) {
854                 int mosi, miso, ss, sck;
855
856                 robo->ops = &spigpio;
857                 robo->devid = DEVID5325;
858
859                 /* Init GPIO mapping. Default 2, 3, 4, 5 */
860                 ss = getgpiopin(vars, "robo_ss", 2);
861                 if (ss == GPIO_PIN_NOTDEFINED) {
862                         ET_ERROR(("robo_attach: robo_ss gpio fail: GPIO 2 in use"));
863                         goto error;
864                 }
865                 robo->ss = 1 << ss;
866                 sck = getgpiopin(vars, "robo_sck", 3);
867                 if (sck == GPIO_PIN_NOTDEFINED) {
868                         ET_ERROR(("robo_attach: robo_sck gpio fail: GPIO 3 in use"));
869                         goto error;
870                 }
871                 robo->sck = 1 << sck;
872                 mosi = getgpiopin(vars, "robo_mosi", 4);
873                 if (mosi == GPIO_PIN_NOTDEFINED) {
874                         ET_ERROR(("robo_attach: robo_mosi gpio fail: GPIO 4 in use"));
875                         goto error;
876                 }
877                 robo->mosi = 1 << mosi;
878                 miso = getgpiopin(vars, "robo_miso", 5);
879                 if (miso == GPIO_PIN_NOTDEFINED) {
880                         ET_ERROR(("robo_attach: robo_miso gpio fail: GPIO 5 in use"));
881                         goto error;
882                 }
883                 robo->miso = 1 << miso;
884                 ET_MSG(("%s: ss %d sck %d mosi %d miso %d\n", __FUNCTION__,
885                         ss, sck, mosi, miso));
886         }
887
888         /* sanity check */
889         ASSERT(robo->ops);
890         ASSERT(robo->ops->write_reg);
891         ASSERT(robo->ops->read_reg);
892         ASSERT((robo->devid == DEVID5325) ||
893                (robo->devid == DEVID5395) ||
894                (robo->devid == DEVID5397) ||
895                (robo->devid == DEVID5398) ||
896                (robo->devid == DEVID53115));
897
898         bcm_robo_reset(robo);
899         config_attach(robo);
900
901         return robo;
902
903 error:
904         MFREE(sb_osh(robo->sbh), robo, sizeof(robo_info_t));
905         return NULL;
906 }
907
908 /* Release access to the RoboSwitch */
909 void
910 bcm_robo_detach(robo_info_t *robo)
911 {
912         config_detach(robo);
913         MFREE(sb_osh(robo->sbh), robo, sizeof(robo_info_t));
914 }
915
916 /* Enable the device and set it to a known good state */
917 int
918 bcm_robo_enable_device(robo_info_t *robo)
919 {
920         uint8 reg_offset, reg_val;
921         int ret = 0;
922
923         /* Enable management interface access */
924         if (robo->ops->enable_mgmtif)
925                 robo->ops->enable_mgmtif(robo);
926
927         if (robo->devid == DEVID5398) {
928                 /* Disable unused ports: port 6 and 7 */
929                 for (reg_offset = REG_CTRL_PORT6; reg_offset <= REG_CTRL_PORT7; reg_offset ++) {
930                         /* Set bits [1:0] to disable RX and TX */
931                         reg_val = 0x03;
932                         robo->ops->write_reg(robo, PAGE_CTRL, reg_offset, &reg_val,
933                                              sizeof(reg_val));
934                 }
935         }
936
937         if (robo->devid == DEVID5325) {
938                 /* Must put the switch into Reverse MII mode! */
939
940                 /* MII port state override (page 0 register 14) */
941                 robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val, sizeof(reg_val));
942
943                 /* Bit 4 enables reverse MII mode */
944                 if (!(reg_val & (1 << 4))) {
945                         /* Enable RvMII */
946                         reg_val |= (1 << 4);
947                         robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
948                                              sizeof(reg_val));
949
950                         /* Read back */
951                         robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, &reg_val,
952                                             sizeof(reg_val));
953                         if (!(reg_val & (1 << 4))) {
954                                 ET_ERROR(("robo_enable_device: enabling RvMII mode failed\n"));
955                                 ret = -1;
956                         }
957                 }
958         }
959
960         /* Disable management interface access */
961         if (robo->ops->disable_mgmtif)
962                 robo->ops->disable_mgmtif(robo);
963
964         return ret;
965 }
966
967
968 void bcm_robo_set_macaddr(robo_info_t *robo, char *mac_addr)
969 {
970         uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 };
971
972         if (mac_addr != NULL)
973                 memcpy(robo->macaddr, mac_addr, 6);
974
975         mac_addr = robo->macaddr;
976
977         /* setup mac address */
978         arl_entry[0] = mac_addr[5];
979         arl_entry[1] = mac_addr[4];
980         arl_entry[2] = mac_addr[3];
981         arl_entry[3] = mac_addr[2];
982         arl_entry[4] = mac_addr[1];
983         arl_entry[5] = mac_addr[0];
984
985         if (robo->devid == DEVID5325) {
986                 /* Init the entry 1 of the bin */
987                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1, \
988                                      arl_entry1, sizeof(arl_entry1));
989                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1, \
990                                      arl_entry1, 1);
991
992                 /* Init the entry 0 of the bin */
993                 arl_entry[6] = 0x8;             /* Port Id: MII */
994                 arl_entry[7] = 0xc0;    /* Static Entry, Valid */
995
996                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \
997                                      arl_entry, sizeof(arl_entry));
998                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
999                                      arl_entry, ETHER_ADDR_LEN);
1000
1001         } else {
1002                 /* Initialize the MAC Addr Index Register */
1003                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
1004                                      arl_entry, ETHER_ADDR_LEN);
1005         }
1006 }
1007
1008 static int handle_reset(void *driver, char *buf, int nr)
1009 {
1010         ROBO_START(driver);
1011         bcm_robo_reset(robo);
1012         ROBO_END(driver);
1013
1014         return 0;
1015 }
1016
1017
1018 static int handle_enable_read(void *driver, char *buf, int nr)
1019 {
1020         int ret;
1021         uint8 val8;
1022
1023         ROBO_START(driver);
1024         robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1025         ret = sprintf(buf, "%d\n", !!(val8 & (1 << 1)));
1026         ROBO_END(driver);
1027
1028         return ret;
1029 }
1030
1031 static int handle_enable_write(void *driver, char *buf, int nr)
1032 {
1033         uint8 val8;
1034
1035 /* printk(KERN_WARNING "bcmrobo.c: handle_enable_write\n"); */
1036
1037         ROBO_START(driver);
1038         robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1039         val8 &= ~(1 << 1);
1040         val8 |= ((buf[0] == '1') << 1);
1041         robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8));
1042         ROBO_END(driver);
1043
1044         return 0;
1045 }
1046
1047 static int handle_enable_vlan_read(void *driver, char *buf, int nr)
1048 {
1049         uint8 val8;
1050
1051         ROBO_START(driver);
1052         robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
1053         ROBO_END(driver);
1054
1055         return sprintf(buf, "%d\n", (((val8 & (1 << 7)) == (1 << 7)) ? 1 : 0));
1056 }
1057 static int handle_enable_vlan_write(void *driver, char *buf, int nr)
1058 {
1059         int disable = ((buf[0] != '1') ? 1 : 0);
1060
1061         uint8 val8;
1062         uint16 val16;
1063         pdesc_t *pdesc;
1064         int pdescsz;
1065         uint16 vid;
1066         uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 };
1067
1068 /* printk(KERN_WARNING "bcmrobo.c: handle_enable_vlan_write\n"); */
1069
1070         ROBO_START(driver);
1071
1072         /* setup global vlan configuration */
1073         /* VLAN Control 0 Register (Page 0x34, Address 0) */
1074         val8 = disable ? 0 : 
1075                 ((1 << 7) |             /* enable/disable 802.1Q VLAN */
1076                 (3 << 5));              /* individual VLAN learning mode */
1077         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8));
1078
1079         /* VLAN Control 1 Register (Page 0x34, Address 1) */
1080         val8 = disable ? 0 : 
1081                 ((1 << 2) |             /* enable/disable RSV multicast V Fwdmap */
1082                 (1 << 3));              /* enable/disable RSV multicast V Untagmap */
1083         if (robo->devid == DEVID5325)
1084                 val8 |= disable ? 0 : (1 << 1);         /* enable/disable RSV multicast V Tagging */
1085         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8));
1086
1087         if ( disable == 0 ) {           /* FIXME: ok to stop here when disabling? */
1088                 arl_entry[0] = robo->macaddr[5];
1089                 arl_entry[1] = robo->macaddr[4];
1090                 arl_entry[2] = robo->macaddr[3];
1091                 arl_entry[3] = robo->macaddr[2];
1092                 arl_entry[4] = robo->macaddr[1];
1093                 arl_entry[5] = robo->macaddr[0];
1094
1095                 if (robo->devid == DEVID5325) {
1096                         /* Init the entry 1 of the bin */
1097                         robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1, \
1098                                              arl_entry1, sizeof(arl_entry1));
1099                         robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1, \
1100                                              arl_entry1, 1);
1101
1102                         /* Init the entry 0 of the bin */
1103                         arl_entry[6] = 0x8;             /* Port Id: MII */
1104                         arl_entry[7] = 0xc0;    /* Static Entry, Valid */
1105
1106                         robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \
1107                                              arl_entry, sizeof(arl_entry));
1108                         robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
1109                                              arl_entry, ETHER_ADDR_LEN);
1110
1111                         /* VLAN Control 4 Register (Page 0x34, Address 4) */
1112                         val8 = (1 << 6);                /* drop frame with VID violation */
1113                         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8));
1114
1115                         /* VLAN Control 5 Register (Page 0x34, Address 5) */
1116                         val8 = (1 << 3);                /* drop frame when miss V table */
1117                         robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8));
1118
1119                         pdesc = pdesc25;
1120                         pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
1121                 } else {
1122                         /* Initialize the MAC Addr Index Register */
1123                         robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \
1124                                              arl_entry, ETHER_ADDR_LEN);
1125
1126                         pdesc = pdesc97;
1127                         pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
1128                 }
1129
1130                 /* setup each vlan. max. 16 vlans. */
1131                 /* force vlan id to be equal to vlan number */
1132                 for (vid = 0; vid < VLAN_NUMVLANS; vid ++) {
1133
1134                         /* Add static ARL entries */
1135                         if (robo->devid == DEVID5325) {
1136                                 val8 = vid;
1137                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E0, \
1138                                                      &val8, sizeof(val8));
1139                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \
1140                                                      &val8, sizeof(val8));
1141
1142                                 /* Write the entry */
1143                                 val8 = 0x80;
1144                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
1145                                                      &val8, sizeof(val8));
1146                                 /* Wait for write to complete */
1147                                 SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
1148                                          &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1149                                          100 /* usec */);
1150                         } else {
1151                                 /* Set the VLAN Id in VLAN ID Index Register */
1152                                 val8 = vid;
1153                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \
1154                                                      &val8, sizeof(val8));
1155
1156                                 /* Set the MAC addr and VLAN Id in ARL Table MAC/VID Entry 0
1157                                  * Register.
1158                                  */
1159                                 arl_entry[6] = vid;
1160                                 arl_entry[7] = 0x0;
1161                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \
1162                                                      arl_entry, sizeof(arl_entry));
1163
1164                                 /* Set the Static bit , Valid bit and Port ID fields in
1165                                  * ARL Table Data Entry 0 Register
1166                                  */
1167                                 val16 = 0xc008;
1168                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_DAT_E0, \
1169                                                      &val16, sizeof(val16));
1170
1171                                 /* Clear the ARL_R/W bit and set the START/DONE bit in
1172                                  * the ARL Read/Write Control Register.
1173                                  */
1174                                 val8 = 0x80;
1175                                 robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
1176                                                      &val8, sizeof(val8));
1177                                 /* Wait for write to complete */
1178                                 SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \
1179                                          &val8, sizeof(val8)), ((val8 & 0x80) != 0)),
1180                                          100 /* usec */);
1181                         }
1182                 }
1183         }
1184
1185         ROBO_END(driver);
1186         return 0;
1187 }
1188
1189 static int handle_vlan_port_read(void *driver, char *buf, int nr)
1190 {
1191         /* FIXME: yeah, some work is missing here */
1192         return sprintf(buf, "bcmrobo.c: handle_vlan_port_read unimplimented\n");
1193 }
1194
1195 static int handle_vlan_port_write(void *driver, char *buf, int nr)
1196 {
1197
1198         switch_driver *d = (switch_driver *) driver;
1199         switch_vlan_config *c = switch_parse_vlan(d, buf);
1200
1201         uint8 val8;
1202         uint16 val16;
1203         uint32 val32;
1204         int j;
1205         pdesc_t *pdesc;
1206         int pdescsz;
1207
1208 /* printk(KERN_WARNING "bcmrobo.c: handle_vlan_port_write, nr %d\n", nr); */
1209
1210         if (c == NULL)
1211                 return -EINVAL;
1212
1213         ROBO_START(driver);
1214
1215         if (robo->devid == DEVID5325) {
1216                 pdesc = pdesc25;
1217                 pdescsz = sizeof(pdesc25) / sizeof(pdesc_t);
1218         } else {
1219                 pdesc = pdesc97;
1220                 pdescsz = sizeof(pdesc97) / sizeof(pdesc_t);
1221         }
1222
1223
1224         for (j = 0; j < d->ports; j++) {
1225                 if ((c->untag | c->pvid) & (1 << j))
1226                         if ((j != d->cpuport) || (c->untag & (1 << j))) {
1227
1228                                 /* change default vlan tag */
1229
1230 /* printk(KERN_WARNING "bcmrobo.c: set default vlan tag, port %d -> vlan %d\n", j, nr); */
1231
1232                                 val16 = ((0 << 13) |            /* priority - always 0 */
1233                                         nr);                    /* vlan id */
1234                                 robo->ops->write_reg(robo, PAGE_VLAN, pdesc[j].ptagr, &val16, sizeof(val16));
1235                         }
1236         }
1237
1238
1239         if (robo->devid == DEVID5325) {
1240                 val32 = ((c->untag << 6) |              /* untag enable */
1241                          c->port);                      /* vlan members */
1242                 val32 |= ((1 << 20) |           /* valid write */
1243                           ((nr >> 4) << 12));  /* vlan id bit[11:4] */
1244                 /* VLAN Write Register (Page 0x34, Address 0x08-0x0B) */
1245                 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE, &val32,
1246                                      sizeof(val32));
1247                 /* VLAN Table Access Register (Page 0x34, Address 0x06-0x07) */
1248                 val16 = ((1 << 13) |    /* start command */
1249                          (1 << 12) |    /* write state */
1250                          nr);          /* vlan id */
1251                 robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS, &val16,
1252                                      sizeof(val16));
1253         } else {
1254                 uint8 vtble, vtbli, vtbla;
1255                 val32 = ((c->untag << 9) |              /* untag enable */
1256                          c->port);                      /* vlan members */
1257
1258                 if ((robo->devid == DEVID5395) || (robo->devid == DEVID53115)) {
1259                         vtble = REG_VTBL_ENTRY_5395;
1260                         vtbli = REG_VTBL_INDX_5395;
1261                         vtbla = REG_VTBL_ACCESS_5395;
1262                 } else {
1263                         vtble = REG_VTBL_ENTRY;
1264                         vtbli = REG_VTBL_INDX;
1265                         vtbla = REG_VTBL_ACCESS;
1266                 }
1267
1268                 /* VLAN Table Entry Register (Page 0x05, Address 0x63-0x66/0x83-0x86) */
1269                 robo->ops->write_reg(robo, PAGE_VTBL, vtble, &val32,
1270                                      sizeof(val32));
1271                 /* VLAN Table Address Index Reg (Page 0x05, Address 0x61-0x62/0x81-0x82) */
1272                 val16 = nr;        /* vlan id */
1273                 robo->ops->write_reg(robo, PAGE_VTBL, vtbli, &val16,
1274                                      sizeof(val16));
1275
1276                 /* VLAN Table Access Register (Page 0x34, Address 0x60/0x80) */
1277                 val8 = ((1 << 7) |      /* start command */
1278                         0);             /* write */
1279                 robo->ops->write_reg(robo, PAGE_VTBL, vtbla, &val8,
1280                                      sizeof(val8));
1281         }
1282
1283         ROBO_END(driver);
1284         return 0;
1285 }
1286
1287 static int __init config_attach(robo_info_t *robo)
1288 {
1289         switch_config cfg[] = {
1290                 {"enable", handle_enable_read, handle_enable_write},
1291                 {"reset", NULL, handle_reset},
1292                 {"enable_vlan", handle_enable_vlan_read, handle_enable_vlan_write},
1293                 {NULL, NULL, NULL}
1294         };
1295         switch_config vlan[] = {
1296                 {"ports", handle_vlan_port_read, handle_vlan_port_write},
1297                 {NULL, NULL, NULL}
1298         };
1299         switch_driver driver = {
1300                 name: DRIVER_NAME,
1301                 version: DRIVER_VERSION,
1302                 interface: robo->name,
1303                 cpuport: 8,
1304                 ports: 9,
1305                 vlans: 16,
1306                 driver_handlers: cfg,
1307                 port_handlers: NULL,
1308                 vlan_handlers: vlan,
1309         };
1310         if (robo->devid == DEVID5325) {
1311                 driver.ports = 6;
1312                 driver.cpuport = 5;
1313         }
1314         driver.priv = (void *) robo;
1315
1316         return switch_register_driver(&driver);
1317 }
1318
1319 static void __exit config_detach(robo_info_t *robo)
1320 {
1321         switch_unregister_driver(DRIVER_NAME);
1322 }
1323
1324