/*
- * Broadcom BCM5325E/536x switch configuration module
+ * ADMTEK Adm6996 switch configuration module
*
* Copyright (C) 2005 Felix Fietkau <nbd@nbd.name>
*
#include <linux/delay.h>
#include <asm/uaccess.h>
-#include "gpio.h"
#include "switch-core.h"
+#include "gpio.h"
#define DRIVER_NAME "adm6996"
+#define DRIVER_VERSION "0.01"
-static int eecs = 2;
-static int eesk = 3;
-static int eedi = 5;
-static int eerc = 6;
+static int eecs = 0;
+static int eesk = 0;
+static int eedi = 0;
+static int eerc = 0;
static int force = 0;
MODULE_AUTHOR("Felix Fietkau <openwrt@nbd.name>");
#define adm_write16(cs, w) { __u16 val = hton16(w); adm_write(cs, (__u8 *)&val, sizeof(val)*8); }
#define adm_write32(cs, i) { uint32 val = hton32(i); adm_write(cs, (__u8 *)&val, sizeof(val)*8); }
+#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
+
+#if defined(BCMGPIO2) || defined(BCMGPIO)
+extern char *nvram_get(char *name);
-extern int getintvar(char **vars, char *name);
+/* Return gpio pin number assigned to the named pin */
+/*
+* Variable should be in format:
+*
+* gpio<N>=pin_name
+*
+* 'def_pin' is returned if there is no such variable found.
+*/
+static unsigned int getgpiopin(char *pin_name, unsigned int def_pin)
+{
+ char name[] = "gpioXXXX";
+ char *val;
+ unsigned int pin;
+
+ /* Go thru all possibilities till a match in pin name */
+ for (pin = 0; pin < 16; pin ++) {
+ sprintf(name, "gpio%d", pin);
+ val = nvram_get(name);
+ if (val && !strcmp(val, pin_name))
+ return pin;
+ }
+ return def_pin;
+}
+#endif
static void adm_write(int cs, char *buf, unsigned int bits)
/* Bits in VLAN port mapping */
static int vlan_ports[] = { 1 << 0, 1 << 2, 1 << 4, 1 << 6, 1 << 7, 1 << 8 };
-static int handle_vlan_port_read(char *buf, int nr)
+static int handle_vlan_port_read(void *driver, char *buf, int nr)
{
int ports, i, c, len = 0;
for (i = 0; i <= 5; i++) {
if (ports & vlan_ports[i]) {
c = adm_rreg(0, port_conf[i]);
- len += sprintf(buf + len, (c & (1 << 4) ? "%dt\t" : (i == 5 ? "%du\t" : "%d\t")), i);
+
+ len += sprintf(buf + len, "%d", i);
+ if (c & (1 << 4)) {
+ buf[len++] = 't';
+ if (((c & (0xf << 10)) >> 10) == nr)
+ buf[len++] = '*';
+ } else if (i == 5)
+ buf[len++] = 'u';
+
+ buf[len++] = '\t';
}
}
len += sprintf(buf + len, "\n");
return len;
}
-static int handle_vlan_port_write(char *buf, int nr)
+static int handle_vlan_port_write(void *driver, char *buf, int nr)
{
- int i, c, ports;
- int map = switch_parse_vlan(buf);
+ int i, cfg, ports;
+ switch_driver *d = (switch_driver *) driver;
+ switch_vlan_config *c = switch_parse_vlan(d, buf);
- if (map == -1)
+ if (c == NULL)
return -1;
ports = adm_rreg(0, 0x13 + nr);
- for (i = 0; i <= 5; i++) {
- if (map & (1 << i)) {
+ for (i = 0; i < d->ports; i++) {
+ if (c->port & (1 << i)) {
ports |= vlan_ports[i];
- c = adm_rreg(0, port_conf[i]);
+ cfg = adm_rreg(0, port_conf[i]);
/* Tagging */
- if (map & (1 << (8 + i)))
- c |= (1 << 4);
+ if (c->untag & (1 << i))
+ cfg &= ~(1 << 4);
else
- c &= ~(1 << 4);
-
- c = (c & ~(0xf << 10)) | (nr << 10);
+ cfg |= (1 << 4);
+
+ if ((c->untag | c->pvid) & (1 << i)) {
+ cfg = (cfg & ~(0xf << 10)) | (nr << 10);
+ }
- adm_wreg(port_conf[i], (__u16) c);
+ adm_wreg(port_conf[i], (__u16) cfg);
} else {
ports &= ~(vlan_ports[i]);
}
return 0;
}
-static int handle_port_enable_read(char *buf, int nr)
+static int handle_port_enable_read(void *driver, char *buf, int nr)
{
return sprintf(buf, "%d\n", ((adm_rreg(0, port_conf[nr]) & (1 << 5)) ? 0 : 1));
}
-static int handle_port_enable_write(char *buf, int nr)
+static int handle_port_enable_write(void *driver, char *buf, int nr)
{
int reg = adm_rreg(0, port_conf[nr]);
return 0;
}
-static int handle_port_media_read(char *buf, int nr)
+static int handle_port_media_read(void *driver, char *buf, int nr)
{
int len;
int media = 0;
return len + sprintf(buf + len, "\n");
}
-static int handle_port_media_write(char *buf, int nr)
+static int handle_port_media_write(void *driver, char *buf, int nr)
{
int media = switch_parse_media(buf);
int reg = adm_rreg(0, port_conf[nr]);
return 0;
}
-static int handle_vlan_enable_read(char *buf, int nr)
+static int handle_vlan_enable_read(void *driver, char *buf, int nr)
{
return sprintf(buf, "%d\n", ((adm_rreg(0, 0x11) & (1 << 5)) ? 1 : 0));
}
-static int handle_vlan_enable_write(char *buf, int nr)
+static int handle_vlan_enable_write(void *driver, char *buf, int nr)
{
int reg = adm_rreg(0, 0x11);
return 0;
}
-static int handle_reset(char *buf, int nr)
+static int handle_reset(void *driver, char *buf, int nr)
{
int i;
+ u32 cfg;
/*
* Reset sequence: RC high->low(100ms)->high(30ms)
* reset logic therefore we must explicitly perform the
* sequence in software.
*/
- /* Keep RC high for at least 20ms */
- adm_enout(eerc, eerc);
- for (i = 0; i < 20; i ++)
- udelay(1000);
- /* Keep RC low for at least 100ms */
- adm_enout(eerc, 0);
- for (i = 0; i < 100; i++)
- udelay(1000);
- /* Set default configuration */
- adm_enout((__u8)(eesk | eedi), eesk);
- /* Keep RC high for at least 30ms */
- adm_enout(eerc, eerc);
- for (i = 0; i < 30; i++)
- udelay(1000);
- /* Leave RC high and disable GPIO outputs */
- adm_disout((__u8)(eecs | eesk | eedi));
-
- /* set up initial configuration for ports */
- for (i = 0; i <= 5; i++) {
- int cfg = 0x8000 | /* Auto MDIX */
- (((i == 5) ? 1 : 0) << 4) | /* Tagging */
- 0xf; /* full duplex, 100Mbps, auto neg, flow ctrl */
- adm_wreg(port_conf[i], cfg);
+ if (eerc) {
+ /* Keep RC high for at least 20ms */
+ adm_enout(eerc, eerc);
+ for (i = 0; i < 20; i ++)
+ udelay(1000);
+ /* Keep RC low for at least 100ms */
+ adm_enout(eerc, 0);
+ for (i = 0; i < 100; i++)
+ udelay(1000);
+ /* Set default configuration */
+ adm_enout((__u8)(eesk | eedi), eesk);
+ /* Keep RC high for at least 30ms */
+ adm_enout(eerc, eerc);
+ for (i = 0; i < 30; i++)
+ udelay(1000);
+ /* Leave RC high and disable GPIO outputs */
+ adm_disout((__u8)(eecs | eesk | eedi));
+
}
+
+ /* set up initial configuration for cpu port */
+ cfg = (0x8000 | /* Auto MDIX */
+ (0xf << 10) | /* PVID */
+ (1 << 4) | /* Tagging */
+ 0xf); /* full duplex, 100Mbps, auto neg, flow ctrl */
+ adm_wreg(port_conf[5], cfg);
/* vlan mode select register (0x11): vlan on, mac clone */
adm_wreg(0x11, 0xff30);
return 0;
}
-static int handle_registers(char *buf, int nr)
+static int handle_registers(void *driver, char *buf, int nr)
{
int i, len = 0;
return len;
}
-static int handle_counters(char *buf, int nr)
+static int handle_counters(void *driver, char *buf, int nr)
{
int i, len = 0;
int ret = 0;
#if defined(BCMGPIO2) || defined(BCMGPIO)
-#ifdef LINUX_2_4
- int boardflags = getintvar(NULL, "boardflags");
-#else
- extern int boardflags;
-#endif
- if ((boardflags & 0x80) || force)
+ int boardflags = atoi(nvram_get("boardflags"));
+
+ if ((boardflags & 0x80) || force) {
+ ret = 1;
+
+ eecs = getgpiopin("adm_eecs", 2);
+ eesk = getgpiopin("adm_eesk", 3);
+ eedi = getgpiopin("adm_eedi", 4);
+ eerc = getgpiopin("adm_rc", 0);
+
+ } else if ((strcmp(nvram_get("boardtype") ?: "", "bcm94710dev") == 0) &&
+ (strncmp(nvram_get("boardnum") ?: "", "42", 2) == 0)) {
+ /* WRT54G v1.1 hack */
+ eecs = 2;
+ eesk = 3;
+ eedi = 5;
+
ret = 1;
- else
+ } else
printk("BFL_ENETADM not set in boardflags. Use force=1 to ignore.\n");
+
+ if (eecs)
+ eecs = (1 << eecs);
+ if (eesk)
+ eesk = (1 << eesk);
+ if (eedi)
+ eedi = (1 << eedi);
+ if (eerc)
+ eerc = (1 << eerc);
#else
ret = 1;
#endif
{NULL, NULL, NULL}
};
switch_config port[] = {
- {"enabled", handle_port_enable_read, handle_port_enable_write},
+ {"enable", handle_port_enable_read, handle_port_enable_write},
{"media", handle_port_media_read, handle_port_media_write},
{NULL, NULL, NULL}
};
};
switch_driver driver = {
name: DRIVER_NAME,
+ version: DRIVER_VERSION,
+ interface: "eth0",
ports: 6,
+ cpuport: 5,
vlans: 16,
driver_handlers: cfg,
port_handlers: port,
vlan_handlers: vlan,
};
- eecs = (1 << eecs);
- eesk = (1 << eesk);
- eedi = (1 << eedi);
-
if (!detect_adm())
return -ENODEV;