On 11/04/11 11:08, Yeoh Chun Yeow wrote: > However, even the board is up without Ethernet cable connecting to the LAN > port 1 or port 0, the message "eth1: link up (100Mbps/Full duplex) is > already printed there.
Yeah, it's still not completely clear to me how these ports are all connected. If one of the Ethernet MACs is connected to the switch, and it would not make sense if that was not the case, then that port will immediately go up. You can compare this with the case where you have an external switch. The only difference is that the switch is integrated in your RouterStation, and you can actually talk to the switch to make it do interesting stuff. If you would have an external switch, there would be a cable between your Ethernet device eth1 and the switch. On the switch, there are two more ports, which are the two sockets on your RouterStation. As soon as eth1 is started, it will go up, because it is connected to the switch. It does not matter if you plug any other cables into the switch. If there are no other cables plugged into the switch, your eth1 is still connected to the switch and the link for eth1 is up. It's just that any packets you send don't go anywhere because no other devices are connected to the switch. You can't even see if any other cables are plugged into the switch without writing specific support code to check for this, just like you wouldn't see in your log whether any other cables are plugged into the external switch. It gets really confusing when the ports you call port 0 and port 1 aren't numbered the same on the switch chip. Like I mentioned somewhere before, port 0 on my switch chip is connected to the port labeled "LAN 4" on my router. Port 1 is "LAN 3", 2 is "LAN 2", 3 is "LAN 1". The only thing you can reasonably expect is that your CPU is connected on port 5. So I wrote a kludge that indeed checks the link state of the attached ports. Could you please use the attached driver and map which sockets on your board connect to which switch ports? If you do # swconfig dev eth1 get link_state It will answer with a list of ports that are up. Please connect and disconnect cables to the three Ethernet sockets on your board and note the effect on that link_state list. I suspect your WAN port might be connected to port 4 of the switch. This is a bit of a special port on the switch chip. The attached driver also checks the chip model. I really hope your log says "ADM6996FC PHY detected." Could you send me the whole log of your RouterStation? It might give me some more clues on how stuff is connected. HTH, Peter. -- I use the GNU Privacy Guard (GnuPG) in combination with Enigmail. You can send me encrypted mail if you want some privacy. My key is available at http://wwwhome.cs.utwente.nl/~lebbing/pubkey.txt
/* * ADM6996 switch driver * * swconfig interface based on ar8216.c * * Copyright (c) 2008 Felix Fietkau <[email protected]> * VLAN support Copyright (c) 2010, 2011 Peter Lebbing <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License v2 as published by the * Free Software Foundation */ #define DEBUG 1 #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/unistd.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> #include <linux/switch.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include "adm6996.h" MODULE_DESCRIPTION("Infineon ADM6996 Switch"); MODULE_AUTHOR("Felix Fietkau, Peter Lebbing <[email protected]>"); MODULE_LICENSE("GPL"); struct adm6996_priv { struct switch_dev dev; struct phy_device *phydev; bool enable_vlan; bool vlan_enabled; /* Current hardware state */ #ifdef DEBUG u16 addr; /* Debugging: register address to operate on */ #endif u16 pvid[ADM_PHY_PORTS]; /* Primary VLAN ID */ u16 vlan_id[ADM_NUM_VLANS]; u8 vlan_table[ADM_NUM_VLANS]; /* bitmap, 1 = port is member */ u8 vlan_tagged[ADM_NUM_VLANS]; /* bitmap, 1 = tagged member */ struct mutex reg_mutex; /* use abstraction for regops, we want to add gpio support in the future */ u16 (*read)(struct phy_device *phydev, enum admreg reg); void (*write)(struct phy_device *phydev, enum admreg reg, u16 val); }; #define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) #define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) static inline u16 r16(struct phy_device *pdev, enum admreg reg) { return phy_to_adm(pdev)->read(pdev, reg); } static inline void w16(struct phy_device *pdev, enum admreg reg, u16 val) { phy_to_adm(pdev)->write(pdev, reg, val); } static u16 adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg) { return phydev->bus->read(phydev->bus, PHYADDR(reg)); } static void adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val) { phydev->bus->write(phydev->bus, PHYADDR(reg), val); } static int adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); if (val->value.i > 1) return -EINVAL; priv->enable_vlan = val->value.i; return 0; }; static int adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); val->value.i = priv->enable_vlan; return 0; }; #ifdef DEBUG static int adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); if (val->value.i > 1023) return -EINVAL; priv->addr = val->value.i; return 0; }; static int adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); val->value.i = priv->addr; return 0; }; static int adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); if (val->value.i > 65535) return -EINVAL; w16(priv->phydev, priv->addr, val->value.i); return 0; }; static int adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); val->value.i = r16(priv->phydev, priv->addr); return 0; }; #endif static int adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) { struct adm6996_priv *priv = to_adm(dev); dev_dbg (&priv->phydev->dev, "set_pvid port %d vlan %d\n", port , vlan); if (vlan > ADM_VLAN_MAX_ID) return -EINVAL; priv->pvid[port] = vlan; return 0; } static int adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) { struct adm6996_priv *priv = to_adm(dev); dev_dbg (&priv->phydev->dev, "get_pvid port %d\n", port); *vlan = priv->pvid[port]; return 0; } static int adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); dev_dbg (&priv->phydev->dev, "set_vid port %d vid %d\n", val->port_vlan, val->value.i); if (val->value.i > ADM_VLAN_MAX_ID) return -EINVAL; priv->vlan_id[val->port_vlan] = val->value.i; return 0; }; static int adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); dev_dbg (&priv->phydev->dev, "get_vid port %d\n", val->port_vlan); val->value.i = priv->vlan_id[val->port_vlan]; return 0; }; static int adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); u8 ports = priv->vlan_table[val->port_vlan]; u8 tagged = priv->vlan_tagged[val->port_vlan]; int i; dev_dbg (&priv->phydev->dev, "get_ports port_vlan %d\n", val->port_vlan); val->len = 0; for (i = 0; i < ADM_PHY_PORTS; i++) { struct switch_port *p; if (!(ports & (1 << i))) continue; p = &val->value.ports[val->len++]; p->id = i; if (tagged & (1 << i)) p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); else p->flags = 0; } return 0; }; static int adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); u8 *ports = &priv->vlan_table[val->port_vlan]; u8 *tagged = &priv->vlan_tagged[val->port_vlan]; int i; dev_dbg (&priv->phydev->dev, "set_ports port_vlan %d ports", val->port_vlan); *ports = 0; *tagged = 0; for (i = 0; i < val->len; i++) { struct switch_port *p = &val->value.ports[i]; #ifdef DEBUG printk(" %d%s", p->id, ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : "")); #endif if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) *tagged |= (1 << p->id); *ports |= (1 << p->id); } #ifdef DEBUG printk("\n"); #endif return 0; }; static int adm6996_get_links(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct adm6996_priv *priv = to_adm(dev); int i; u16 reg; val->len = 0; for (i = 0; i < ADM_PHY_PORTS; i++) { struct switch_port *p; reg = r16(priv->phydev, 0x201 + 0x20 * i); reg = r16(priv->phydev, 0x201 + 0x20 * i); if (!(reg & (1 << 2))) continue; /* if (!(ports & (1 << i))) continue; */ p = &val->value.ports[val->len++]; p->id = i; p->flags = 0; } return 0; }; /* * Precondition: reg_mutex must be held */ static void adm6996_enable_vlan(struct adm6996_priv *priv) { u16 reg; reg = r16(priv->phydev, ADM_OTBE_P2_PVID); reg &= ~(ADM_OTBE_MASK); w16(priv->phydev, ADM_OTBE_P2_PVID, reg); reg = r16(priv->phydev, ADM_IFNTE); reg &= ~(ADM_IFNTE_MASK); w16(priv->phydev, ADM_IFNTE, reg); reg = r16(priv->phydev, ADM_VID_CHECK); reg |= ADM_VID_CHECK_MASK; w16(priv->phydev, ADM_VID_CHECK, reg); reg = r16(priv->phydev, ADM_SYSC0); reg |= ADM_NTTE; reg &= ~(ADM_RVID1); w16(priv->phydev, ADM_SYSC0, reg); reg = r16(priv->phydev, ADM_SYSC3); reg |= ADM_TBV; w16(priv->phydev, ADM_SYSC3, reg); }; /* * Disable VLANs * * Sets VLAN mapping for port-based VLAN with all ports connected to * eachother (this is also the power-on default). * * Precondition: reg_mutex must be held */ static void adm6996_disable_vlan(struct adm6996_priv *priv) { u16 reg; int i; for (i = 0; i < ADM_PHY_PORTS; i++) { reg = ADM_VLAN_FILT_MEMBER_MASK; w16(priv->phydev, ADM_VLAN_FILT_L(i), reg); reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); w16(priv->phydev, ADM_VLAN_FILT_H(i), reg); } reg = r16(priv->phydev, ADM_OTBE_P2_PVID); reg |= ADM_OTBE_MASK; w16(priv->phydev, ADM_OTBE_P2_PVID, reg); reg = r16(priv->phydev, ADM_IFNTE); reg |= ADM_IFNTE_MASK; w16(priv->phydev, ADM_IFNTE, reg); reg = r16(priv->phydev, ADM_VID_CHECK); reg &= ~(ADM_VID_CHECK_MASK); w16(priv->phydev, ADM_VID_CHECK, reg); reg = r16(priv->phydev, ADM_SYSC0); reg &= ~(ADM_NTTE); reg |= ADM_RVID1; w16(priv->phydev, ADM_SYSC0, reg); reg = r16(priv->phydev, ADM_SYSC3); reg &= ~(ADM_TBV); w16(priv->phydev, ADM_SYSC3, reg); } /* * Precondition: reg_mutex must be held */ static void adm6996_apply_port_pvids(struct adm6996_priv *priv) { u16 reg; int i; for (i = 0; i < ADM_PHY_PORTS; i++) { reg = r16(priv->phydev, adm_portcfg[i]); reg &= ~(ADM_PORTCFG_PVID_MASK); reg |= ADM_PORTCFG_PVID(priv->pvid[i]); w16(priv->phydev, adm_portcfg[i], reg); } w16(priv->phydev, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); w16(priv->phydev, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); reg = r16(priv->phydev, ADM_OTBE_P2_PVID); reg &= ~(ADM_P2_PVID_MASK); reg |= ADM_P2_PVID_VAL(priv->pvid[2]); w16(priv->phydev, ADM_OTBE_P2_PVID, reg); reg = ADM_P3_PVID_VAL(priv->pvid[3]); reg |= ADM_P4_PVID_VAL(priv->pvid[4]); w16(priv->phydev, ADM_P3_P4_PVID, reg); w16(priv->phydev, ADM_P5_PVID, ADM_P5_PVID_VAL(priv->pvid[5])); } /* * Precondition: reg_mutex must be held */ static void adm6996_apply_vlan_filters(struct adm6996_priv *priv) { u8 ports, tagged; u16 vid, reg; int i; for (i = 0; i < ADM_NUM_VLANS; i++) { vid = priv->vlan_id[i]; ports = priv->vlan_table[i]; tagged = priv->vlan_tagged[i]; if (ports == 0) { /* Disable VLAN entry */ w16(priv->phydev, ADM_VLAN_FILT_H(i), 0); w16(priv->phydev, ADM_VLAN_FILT_L(i), 0); continue; } reg = ADM_VLAN_FILT_MEMBER(ports); reg |= ADM_VLAN_FILT_TAGGED(tagged); w16(priv->phydev, ADM_VLAN_FILT_L(i), reg); reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); w16(priv->phydev, ADM_VLAN_FILT_H(i), reg); } } static int adm6996_hw_apply(struct switch_dev *dev) { struct adm6996_priv *priv = to_adm(dev); dev_dbg (&priv->phydev->dev, "hw_apply\n"); mutex_lock(&priv->reg_mutex); if (!priv->enable_vlan && priv->vlan_enabled) { adm6996_disable_vlan(priv); priv->vlan_enabled = 0; goto out; } else if (priv->enable_vlan && !priv->vlan_enabled) { adm6996_enable_vlan(priv); priv->vlan_enabled = 1; } adm6996_apply_port_pvids (priv); adm6996_apply_vlan_filters (priv); out: mutex_unlock(&priv->reg_mutex); return 0; } static struct switch_attr adm6996_globals[] = { { .type = SWITCH_TYPE_INT, .name = "enable_vlan", .description = "Enable VLANs", .set = adm6996_set_enable_vlan, .get = adm6996_get_enable_vlan, }, { .type = SWITCH_TYPE_PORTS, .name = "link_state", .description = "Show link state of ports", .get = adm6996_get_links, }, #ifdef DEBUG { .type = SWITCH_TYPE_INT, .name = "addr", .description = "Direct register access: set register address (0 - 1023)", .set = adm6996_set_addr, .get = adm6996_get_addr, }, { .type = SWITCH_TYPE_INT, .name = "data", .description = "Direct register access: read/write to register (0 - 65535)", .set = adm6996_set_data, .get = adm6996_get_data, }, #endif }; static struct switch_attr adm6996_port[] = { }; static struct switch_attr adm6996_vlan[] = { { .type = SWITCH_TYPE_INT, .name = "vid", .description = "VLAN ID", .set = adm6996_set_vid, .get = adm6996_get_vid, }, }; static const struct switch_dev_ops adm6996_ops = { .attr_global = { .attr = adm6996_globals, .n_attr = ARRAY_SIZE(adm6996_globals), }, .attr_port = { .attr = adm6996_port, .n_attr = ARRAY_SIZE(adm6996_port), }, .attr_vlan = { .attr = adm6996_vlan, .n_attr = ARRAY_SIZE(adm6996_vlan), }, .get_port_pvid = adm6996_get_pvid, .set_port_pvid = adm6996_set_pvid, .get_vlan_ports = adm6996_get_ports, .set_vlan_ports = adm6996_set_ports, .apply_config = adm6996_hw_apply, }; static int adm6996_config_init(struct phy_device *pdev) { struct adm6996_priv *priv; struct switch_dev *swdev; int i, ret; u16 test, old; if (pdev->addr != 0) { pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY %x.\n" , pdev->attached_dev->name, pdev->addr); return 0; } priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; mutex_init(&priv->reg_mutex); priv->phydev = pdev; priv->read = adm6996_read_mii_reg; priv->write = adm6996_write_mii_reg; pdev->priv = priv; /* Detect type of chip */ old = r16(pdev, ADM_VID_CHECK); test = old ^ (1 << 12); w16(pdev, ADM_VID_CHECK, test); test ^= r16(pdev, ADM_VID_CHECK); if (test & (1 << 12)) { /* * Bit 12 of this register is read-only. * This is the FC model. */ printk("%s: ADM6996FC PHY detected.\n", pdev->attached_dev->name); } else { /* Bit 12 is read-write. This is the M model. */ w16(pdev, ADM_VID_CHECK, old); printk("%s: ADM6996M PHY detected.\n", pdev->attached_dev->name); } pdev->supported = ADVERTISED_100baseT_Full; pdev->advertising = ADVERTISED_100baseT_Full; /* initialize port and vlan settings */ for (i = 0; i < ADM_PHY_PORTS - 1; i++) { w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT | ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0)); } w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU); /* reset all ports */ for (i = 0; i < ADM_PHY_PORTS - 1; i++) { w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); } /* Clear VLAN priority map so prio's are unused */ w16 (pdev, ADM_VLAN_PRIOMAP, 0); swdev = &priv->dev; swdev->name = "ADM6996"; swdev->cpu_port = ADM_CPU_PORT; swdev->ports = ADM_PHY_PORTS; swdev->vlans = ADM_NUM_VLANS; swdev->ops = &adm6996_ops; priv->pvid[ADM_WAN_PORT] = 1; for (i = 0; i < ADM_NUM_VLANS; i++) { priv->vlan_id[i] = i; } if ((ret = register_switch(swdev, pdev->attached_dev)) < 0) { kfree(priv); return ret; } return 0; } static int adm6996_read_status(struct phy_device *phydev) { phydev->speed = SPEED_100; phydev->duplex = DUPLEX_FULL; phydev->link = 1; return 0; } static int adm6996_config_aneg(struct phy_device *phydev) { return 0; } static int adm6996_fixup(struct phy_device *dev) { struct mii_bus *bus = dev->bus; u16 reg; /* look for the switch on the bus */ reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; if (reg != ADM_SIG0_VAL) return 0; reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; if (reg != ADM_SIG1_VAL) return 0; dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; return 0; } static int adm6996_probe(struct phy_device *pdev) { return 0; } static void adm6996_remove(struct phy_device *pdev) { kfree(pdev->priv); } static struct phy_driver adm6996_driver = { .name = "Infineon ADM6996", .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, .phy_id_mask = 0xffffffff, .features = PHY_BASIC_FEATURES, .probe = adm6996_probe, .remove = adm6996_remove, .config_init = &adm6996_config_init, .config_aneg = &adm6996_config_aneg, .read_status = &adm6996_read_status, .driver = { .owner = THIS_MODULE,}, }; static int __init adm6996_init(void) { phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); return phy_driver_register(&adm6996_driver); } static void __exit adm6996_exit(void) { phy_driver_unregister(&adm6996_driver); } module_init(adm6996_init); module_exit(adm6996_exit);
/* * ADM6996 switch driver * * Copyright (c) 2008 Felix Fietkau <[email protected]> * Copyright (c) 2010,2011 Peter Lebbing <[email protected]> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License v2 as published by the * Free Software Foundation */ #ifndef __ADM6996_H #define __ADM6996_H #define ADM_PHY_PORTS 6 #define ADM_CPU_PORT 5 #define ADM_WAN_PORT 0 /* FIXME: dynamic ? */ #define ADM_NUM_VLANS 16 #define ADM_VLAN_MAX_ID 4094 enum admreg { ADM_EEPROM_BASE = 0x0, ADM_P0_CFG = ADM_EEPROM_BASE + 1, ADM_P1_CFG = ADM_EEPROM_BASE + 3, ADM_P2_CFG = ADM_EEPROM_BASE + 5, ADM_P3_CFG = ADM_EEPROM_BASE + 7, ADM_P4_CFG = ADM_EEPROM_BASE + 8, ADM_P5_CFG = ADM_EEPROM_BASE + 9, ADM_SYSC0 = ADM_EEPROM_BASE + 0xa, ADM_VLAN_PRIOMAP = ADM_EEPROM_BASE + 0xe, ADM_SYSC3 = ADM_EEPROM_BASE + 0x11, /* Input Force No Tag Enable */ ADM_IFNTE = ADM_EEPROM_BASE + 0x20, ADM_VID_CHECK = ADM_EEPROM_BASE + 0x26, ADM_P0_PVID = ADM_EEPROM_BASE + 0x28, ADM_P1_PVID = ADM_EEPROM_BASE + 0x29, /* Output Tag Bypass Enable and P2 PVID */ ADM_OTBE_P2_PVID = ADM_EEPROM_BASE + 0x2a, ADM_P3_P4_PVID = ADM_EEPROM_BASE + 0x2b, ADM_P5_PVID = ADM_EEPROM_BASE + 0x2c, ADM_EEPROM_EXT_BASE = 0x40, #define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) #define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) ADM_COUNTER_BASE = 0xa0, ADM_SIG0 = ADM_COUNTER_BASE + 0, ADM_SIG1 = ADM_COUNTER_BASE + 1, ADM_PHY_BASE = 0x200, #define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) }; /* Chip identification patterns */ #define ADM_SIG0_MASK 0xfff0 #define ADM_SIG0_VAL 0x1020 #define ADM_SIG1_MASK 0xffff #define ADM_SIG1_VAL 0x0007 enum { ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ ADM_PHYCFG_INIT = ( ADM_PHYCFG_RST | ADM_PHYCFG_SPEED_100 | ADM_PHYCFG_ANEN | ADM_PHYCFG_ANEN_RST ) }; enum { ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ ADM_PORTCFG_PD = (1 << 5), /* Port disable */ ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority * 1 = TOS based priority */ ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ ADM_PORTCFG_INIT = ( ADM_PORTCFG_FC | ADM_PORTCFG_AN | ADM_PORTCFG_SPEED_100 | ADM_PORTCFG_DPLX | ADM_PORTCFG_CAM ), ADM_PORTCFG_CPU = ( ADM_PORTCFG_FC | ADM_PORTCFG_SPEED_100 | ADM_PORTCFG_OT | ADM_PORTCFG_DPLX ), }; #define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) #define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) #define ADM_PORTCFG_PVID_MASK (0xf << 10) #define ADM_IFNTE_MASK (0x3f << 9) #define ADM_VID_CHECK_MASK (0x3f << 6) #define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) #define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) #define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) #define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) #define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) #define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) #define ADM_P2_PVID_MASK 0xff #define ADM_OTBE(n) (((n) & 0x3f) << 8) #define ADM_OTBE_MASK (0x3f << 8) /* ADM_SYSC0 */ enum { ADM_NTTE = (1 << 2), /* New Tag Transmit Enable */ ADM_RVID1 = (1 << 8) /* Replace VLAN ID 1 */ }; /* Tag Based VLAN in ADM_SYSC3 */ #define ADM_TBV (1 << 5) static const u8 adm_portcfg[] = { [0] = ADM_P0_CFG, [1] = ADM_P1_CFG, [2] = ADM_P2_CFG, [3] = ADM_P3_CFG, [4] = ADM_P4_CFG, [5] = ADM_P5_CFG, }; /* Fields in ADM_VLAN_FILT_L(x) */ #define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) #define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) #define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) #define ADM_VLAN_FILT_MEMBER_MASK 0x3f /* Fields in ADM_VLAN_FILT_H(x) */ #define ADM_VLAN_FILT_VALID (1 << 15) #define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) /* * Split the register address in phy id and register * it will get combined again by the mdio bus op */ #define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) #endif
_______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/mailman/listinfo/openwrt-devel
