Changeset 26865


Ignore:
Timestamp:
2011-05-09T17:21:58+02:00 (7 years ago)
Author:
blogic
Message:

[PATCH v3] (respin) 802.1Q VLAN support for ADM6996M/ADM6996FC

This patch adds 802.1Q VLAN support for the ADM6996M chip.

The driver is loaded for both the FC and M model. It will detect which of the
two chips is connected. The FC model is initialised, but no further
functionality is offered.

The PHY driver will always report "100 Mbit/s, link up", for both the M and FC
models. This reflects the fact that the link between switch chip and Ethernet
MAC is always on[1].

Further documentation can be found in the kernel's
Documentation/networking/adm6996.txt

Signed-of-By: Peter Lebbing <peter@…>

Location:
trunk/target/linux/generic
Files:
2 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/target/linux/generic/files/drivers/net/phy/adm6996.c

    r21952 r26865  
    22 * ADM6996 switch driver 
    33 * 
     4 * swconfig interface based on ar8216.c 
     5 * 
    46 * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> 
     7 * VLAN support Copyright (c) 2010, 2011 Peter Lebbing <peter@digitalbrains.com> 
    58 * 
    69 * This program is free software; you can redistribute  it and/or modify it 
     
    811 * Free Software Foundation 
    912 */ 
     13 
     14/*#define DEBUG 1*/ 
    1015#include <linux/kernel.h> 
    1116#include <linux/string.h> 
     
    2530#include <linux/ethtool.h> 
    2631#include <linux/phy.h> 
     32#include <linux/switch.h> 
    2733 
    2834#include <asm/io.h> 
     
    3238 
    3339MODULE_DESCRIPTION("Infineon ADM6996 Switch"); 
    34 MODULE_AUTHOR("Felix Fietkau"); 
     40MODULE_AUTHOR("Felix Fietkau, Peter Lebbing <peter@digitalbrains.com>"); 
    3541MODULE_LICENSE("GPL"); 
    3642 
     43enum adm6996_model { 
     44        ADM6996FC, 
     45        ADM6996M 
     46}; 
     47 
     48static const char * const adm6996_model_name[] = 
     49{ 
     50        "ADM6996FC", 
     51        "ADM6996M" 
     52}; 
     53 
    3754struct adm6996_priv { 
     55        struct switch_dev dev; 
     56        struct phy_device *phydev; 
     57 
     58        enum adm6996_model model; 
     59 
     60        bool enable_vlan; 
     61        bool vlan_enabled;      /* Current hardware state */ 
     62 
     63#ifdef DEBUG 
     64        u16 addr;               /* Debugging: register address to operate on */ 
     65#endif 
     66 
     67        u16 pvid[ADM_NUM_PORTS];        /* Primary VLAN ID */ 
     68 
     69        u16 vlan_id[ADM_NUM_VLANS]; 
     70        u8 vlan_table[ADM_NUM_VLANS];   /* bitmap, 1 = port is member */ 
     71        u8 vlan_tagged[ADM_NUM_VLANS];  /* bitmap, 1 = tagged member */ 
     72 
     73        struct mutex reg_mutex; 
     74 
    3875        /* use abstraction for regops, we want to add gpio support in the future */ 
    3976        u16 (*read)(struct phy_device *phydev, enum admreg reg); 
     
    4178}; 
    4279 
    43 #define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) 
    44  
     80#define to_adm(_dev) container_of(_dev, struct adm6996_priv, dev) 
     81#define phy_to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) 
    4582 
    4683static inline u16 
    4784r16(struct phy_device *pdev, enum admreg reg) 
    4885{ 
    49         return to_adm(pdev)->read(pdev, reg); 
     86        return phy_to_adm(pdev)->read(pdev, reg); 
    5087} 
    5188 
     
    5390w16(struct phy_device *pdev, enum admreg reg, u16 val) 
    5491{ 
    55         to_adm(pdev)->write(pdev, reg, val); 
     92        phy_to_adm(pdev)->write(pdev, reg, val); 
    5693} 
    5794 
     
    69106} 
    70107 
     108static int 
     109adm6996_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, 
     110                        struct switch_val *val) 
     111{ 
     112        struct adm6996_priv *priv = to_adm(dev); 
     113 
     114        if (val->value.i > 1) 
     115                return -EINVAL; 
     116 
     117        priv->enable_vlan = val->value.i; 
     118 
     119        return 0; 
     120}; 
     121 
     122static int 
     123adm6996_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, 
     124                        struct switch_val *val) 
     125{ 
     126        struct adm6996_priv *priv = to_adm(dev); 
     127 
     128        val->value.i = priv->enable_vlan; 
     129 
     130        return 0; 
     131}; 
     132 
     133#ifdef DEBUG 
     134 
     135static int 
     136adm6996_set_addr(struct switch_dev *dev, const struct switch_attr *attr, 
     137                 struct switch_val *val) 
     138{ 
     139        struct adm6996_priv *priv = to_adm(dev); 
     140 
     141        if (val->value.i > 1023) 
     142                return -EINVAL; 
     143 
     144        priv->addr = val->value.i; 
     145 
     146        return 0; 
     147}; 
     148 
     149static int 
     150adm6996_get_addr(struct switch_dev *dev, const struct switch_attr *attr, 
     151                 struct switch_val *val) 
     152{ 
     153        struct adm6996_priv *priv = to_adm(dev); 
     154 
     155        val->value.i = priv->addr; 
     156 
     157        return 0; 
     158}; 
     159 
     160static int 
     161adm6996_set_data(struct switch_dev *dev, const struct switch_attr *attr, 
     162                 struct switch_val *val) 
     163{ 
     164        struct adm6996_priv *priv = to_adm(dev); 
     165 
     166        if (val->value.i > 65535) 
     167                return -EINVAL; 
     168 
     169        w16(priv->phydev, priv->addr, val->value.i); 
     170 
     171        return 0; 
     172}; 
     173 
     174static int 
     175adm6996_get_data(struct switch_dev *dev, const struct switch_attr *attr, 
     176                 struct switch_val *val) 
     177{ 
     178        struct adm6996_priv *priv = to_adm(dev); 
     179 
     180        val->value.i = r16(priv->phydev, priv->addr); 
     181 
     182        return 0; 
     183}; 
     184 
     185#endif /* def DEBUG */ 
     186 
     187static int 
     188adm6996_set_pvid(struct switch_dev *dev, int port, int vlan) 
     189{ 
     190        struct adm6996_priv *priv = to_adm(dev); 
     191 
     192        dev_dbg (&priv->phydev->dev, "set_pvid port %d vlan %d\n", port 
     193                        , vlan); 
     194 
     195        if (vlan > ADM_VLAN_MAX_ID) 
     196                return -EINVAL; 
     197 
     198        priv->pvid[port] = vlan; 
     199 
     200        return 0; 
     201} 
     202 
     203static int 
     204adm6996_get_pvid(struct switch_dev *dev, int port, int *vlan) 
     205{ 
     206        struct adm6996_priv *priv = to_adm(dev); 
     207 
     208        dev_dbg (&priv->phydev->dev, "get_pvid port %d\n", port); 
     209        *vlan = priv->pvid[port]; 
     210 
     211        return 0; 
     212} 
     213 
     214static int 
     215adm6996_set_vid(struct switch_dev *dev, const struct switch_attr *attr, 
     216                struct switch_val *val) 
     217{ 
     218        struct adm6996_priv *priv = to_adm(dev); 
     219 
     220        dev_dbg (&priv->phydev->dev, "set_vid port %d vid %d\n", val->port_vlan, 
     221                        val->value.i); 
     222 
     223        if (val->value.i > ADM_VLAN_MAX_ID) 
     224                return -EINVAL; 
     225 
     226        priv->vlan_id[val->port_vlan] = val->value.i; 
     227 
     228        return 0; 
     229}; 
     230 
     231static int 
     232adm6996_get_vid(struct switch_dev *dev, const struct switch_attr *attr, 
     233                struct switch_val *val) 
     234{ 
     235        struct adm6996_priv *priv = to_adm(dev); 
     236 
     237        dev_dbg (&priv->phydev->dev, "get_vid port %d\n", val->port_vlan); 
     238 
     239        val->value.i = priv->vlan_id[val->port_vlan]; 
     240 
     241        return 0; 
     242}; 
     243 
     244static int 
     245adm6996_get_ports(struct switch_dev *dev, struct switch_val *val) 
     246{ 
     247        struct adm6996_priv *priv = to_adm(dev); 
     248        u8 ports = priv->vlan_table[val->port_vlan]; 
     249        u8 tagged = priv->vlan_tagged[val->port_vlan]; 
     250        int i; 
     251 
     252        dev_dbg (&priv->phydev->dev, "get_ports port_vlan %d\n", 
     253                        val->port_vlan); 
     254 
     255        val->len = 0; 
     256 
     257        for (i = 0; i < ADM_NUM_PORTS; i++) { 
     258                struct switch_port *p; 
     259 
     260                if (!(ports & (1 << i))) 
     261                        continue; 
     262 
     263                p = &val->value.ports[val->len++]; 
     264                p->id = i; 
     265                if (tagged & (1 << i)) 
     266                        p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); 
     267                else 
     268                        p->flags = 0; 
     269        } 
     270 
     271        return 0; 
     272}; 
     273 
     274static int 
     275adm6996_set_ports(struct switch_dev *dev, struct switch_val *val) 
     276{ 
     277        struct adm6996_priv *priv = to_adm(dev); 
     278        u8 *ports = &priv->vlan_table[val->port_vlan]; 
     279        u8 *tagged = &priv->vlan_tagged[val->port_vlan]; 
     280        int i; 
     281 
     282        dev_dbg (&priv->phydev->dev, "set_ports port_vlan %d ports", 
     283                        val->port_vlan); 
     284 
     285        *ports = 0; 
     286        *tagged = 0; 
     287 
     288        for (i = 0; i < val->len; i++) { 
     289                struct switch_port *p = &val->value.ports[i]; 
     290 
     291#ifdef DEBUG 
     292                pr_cont(" %d%s", p->id, 
     293                       ((p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) ? "T" : 
     294                        "")); 
     295#endif 
     296 
     297                if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) 
     298                        *tagged |= (1 << p->id); 
     299 
     300                *ports |= (1 << p->id); 
     301        } 
     302 
     303#ifdef DEBUG 
     304        pr_cont("\n"); 
     305#endif 
     306 
     307        return 0; 
     308}; 
     309 
     310/* 
     311 * Precondition: reg_mutex must be held 
     312 */ 
     313static void 
     314adm6996_enable_vlan(struct adm6996_priv *priv) 
     315{ 
     316        u16 reg; 
     317 
     318        reg = r16(priv->phydev, ADM_OTBE_P2_PVID); 
     319        reg &= ~(ADM_OTBE_MASK); 
     320        w16(priv->phydev, ADM_OTBE_P2_PVID, reg); 
     321        reg = r16(priv->phydev, ADM_IFNTE); 
     322        reg &= ~(ADM_IFNTE_MASK); 
     323        w16(priv->phydev, ADM_IFNTE, reg); 
     324        reg = r16(priv->phydev, ADM_VID_CHECK); 
     325        reg |= ADM_VID_CHECK_MASK; 
     326        w16(priv->phydev, ADM_VID_CHECK, reg); 
     327        reg = r16(priv->phydev, ADM_SYSC0); 
     328        reg |= ADM_NTTE; 
     329        reg &= ~(ADM_RVID1); 
     330        w16(priv->phydev, ADM_SYSC0, reg); 
     331        reg = r16(priv->phydev, ADM_SYSC3); 
     332        reg |= ADM_TBV; 
     333        w16(priv->phydev, ADM_SYSC3, reg); 
     334 
     335}; 
     336 
     337/* 
     338 * Disable VLANs 
     339 * 
     340 * Sets VLAN mapping for port-based VLAN with all ports connected to 
     341 * eachother (this is also the power-on default). 
     342 * 
     343 * Precondition: reg_mutex must be held 
     344 */ 
     345static void 
     346adm6996_disable_vlan(struct adm6996_priv *priv) 
     347{ 
     348        u16 reg; 
     349        int i; 
     350 
     351        for (i = 0; i < ADM_NUM_PORTS; i++) { 
     352                reg = ADM_VLAN_FILT_MEMBER_MASK; 
     353                w16(priv->phydev, ADM_VLAN_FILT_L(i), reg); 
     354                reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(1); 
     355                w16(priv->phydev, ADM_VLAN_FILT_H(i), reg); 
     356        } 
     357 
     358        reg = r16(priv->phydev, ADM_OTBE_P2_PVID); 
     359        reg |= ADM_OTBE_MASK; 
     360        w16(priv->phydev, ADM_OTBE_P2_PVID, reg); 
     361        reg = r16(priv->phydev, ADM_IFNTE); 
     362        reg |= ADM_IFNTE_MASK; 
     363        w16(priv->phydev, ADM_IFNTE, reg); 
     364        reg = r16(priv->phydev, ADM_VID_CHECK); 
     365        reg &= ~(ADM_VID_CHECK_MASK); 
     366        w16(priv->phydev, ADM_VID_CHECK, reg); 
     367        reg = r16(priv->phydev, ADM_SYSC0); 
     368        reg &= ~(ADM_NTTE); 
     369        reg |= ADM_RVID1; 
     370        w16(priv->phydev, ADM_SYSC0, reg); 
     371        reg = r16(priv->phydev, ADM_SYSC3); 
     372        reg &= ~(ADM_TBV); 
     373        w16(priv->phydev, ADM_SYSC3, reg); 
     374} 
     375 
     376/* 
     377 * Precondition: reg_mutex must be held 
     378 */ 
     379static void 
     380adm6996_apply_port_pvids(struct adm6996_priv *priv) 
     381{ 
     382        u16 reg; 
     383        int i; 
     384 
     385        for (i = 0; i < ADM_NUM_PORTS; i++) { 
     386                reg = r16(priv->phydev, adm_portcfg[i]); 
     387                reg &= ~(ADM_PORTCFG_PVID_MASK); 
     388                reg |= ADM_PORTCFG_PVID(priv->pvid[i]); 
     389                w16(priv->phydev, adm_portcfg[i], reg); 
     390        } 
     391 
     392        w16(priv->phydev, ADM_P0_PVID, ADM_P0_PVID_VAL(priv->pvid[0])); 
     393        w16(priv->phydev, ADM_P1_PVID, ADM_P1_PVID_VAL(priv->pvid[1])); 
     394        reg = r16(priv->phydev, ADM_OTBE_P2_PVID); 
     395        reg &= ~(ADM_P2_PVID_MASK); 
     396        reg |= ADM_P2_PVID_VAL(priv->pvid[2]); 
     397        w16(priv->phydev, ADM_OTBE_P2_PVID, reg); 
     398        reg = ADM_P3_PVID_VAL(priv->pvid[3]); 
     399        reg |= ADM_P4_PVID_VAL(priv->pvid[4]); 
     400        w16(priv->phydev, ADM_P3_P4_PVID, reg); 
     401        w16(priv->phydev, ADM_P5_PVID, ADM_P5_PVID_VAL(priv->pvid[5])); 
     402} 
     403 
     404/* 
     405 * Precondition: reg_mutex must be held 
     406 */ 
     407static void 
     408adm6996_apply_vlan_filters(struct adm6996_priv *priv) 
     409{ 
     410        u8 ports, tagged; 
     411        u16 vid, reg; 
     412        int i; 
     413 
     414        for (i = 0; i < ADM_NUM_VLANS; i++) { 
     415                vid = priv->vlan_id[i]; 
     416                ports = priv->vlan_table[i]; 
     417                tagged = priv->vlan_tagged[i]; 
     418 
     419                if (ports == 0) { 
     420                        /* Disable VLAN entry */ 
     421                        w16(priv->phydev, ADM_VLAN_FILT_H(i), 0); 
     422                        w16(priv->phydev, ADM_VLAN_FILT_L(i), 0); 
     423                        continue; 
     424                } 
     425 
     426                reg = ADM_VLAN_FILT_MEMBER(ports); 
     427                reg |= ADM_VLAN_FILT_TAGGED(tagged); 
     428                w16(priv->phydev, ADM_VLAN_FILT_L(i), reg); 
     429                reg = ADM_VLAN_FILT_VALID | ADM_VLAN_FILT_VID(vid); 
     430                w16(priv->phydev, ADM_VLAN_FILT_H(i), reg); 
     431        } 
     432} 
     433 
     434static int 
     435adm6996_hw_apply(struct switch_dev *dev) 
     436{ 
     437        struct adm6996_priv *priv = to_adm(dev); 
     438 
     439        dev_dbg(&priv->phydev->dev, "hw_apply\n"); 
     440 
     441        mutex_lock(&priv->reg_mutex); 
     442 
     443        if (!priv->enable_vlan) { 
     444                if (priv->vlan_enabled) { 
     445                        adm6996_disable_vlan(priv); 
     446                        priv->vlan_enabled = 0; 
     447                } 
     448                goto out; 
     449        } 
     450 
     451        if (!priv->vlan_enabled) { 
     452                adm6996_enable_vlan(priv); 
     453                priv->vlan_enabled = 1; 
     454        } 
     455 
     456        adm6996_apply_port_pvids(priv); 
     457        adm6996_apply_vlan_filters(priv); 
     458 
     459out: 
     460        mutex_unlock(&priv->reg_mutex); 
     461 
     462        return 0; 
     463} 
     464 
     465/* 
     466 * Reset the switch 
     467 * 
     468 * The ADM6996 can't do a software-initiated reset, so we just initialise the 
     469 * registers we support in this driver. 
     470 * 
     471 * Precondition: reg_mutex must be held 
     472 */ 
     473static void 
     474adm6996_perform_reset (struct adm6996_priv *priv) 
     475{ 
     476        int i; 
     477 
     478        /* initialize port and vlan settings */ 
     479        for (i = 0; i < ADM_NUM_PORTS - 1; i++) { 
     480                w16(priv->phydev, adm_portcfg[i], ADM_PORTCFG_INIT | 
     481                        ADM_PORTCFG_PVID(0)); 
     482        } 
     483        w16(priv->phydev, adm_portcfg[5], ADM_PORTCFG_CPU); 
     484 
     485        /* reset all PHY ports */ 
     486        for (i = 0; i < ADM_PHY_PORTS; i++) { 
     487                w16(priv->phydev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); 
     488        } 
     489 
     490        priv->enable_vlan = 0; 
     491        priv->vlan_enabled = 0; 
     492 
     493        for (i = 0; i < ADM_NUM_PORTS; i++) { 
     494                priv->pvid[i] = 0; 
     495        } 
     496 
     497        for (i = 0; i < ADM_NUM_VLANS; i++) { 
     498                priv->vlan_id[i] = i; 
     499                priv->vlan_table[i] = 0; 
     500                priv->vlan_tagged[i] = 0; 
     501        } 
     502 
     503        if (priv->model == ADM6996M) { 
     504                /* Clear VLAN priority map so prio's are unused */ 
     505                w16 (priv->phydev, ADM_VLAN_PRIOMAP, 0); 
     506 
     507                adm6996_disable_vlan(priv); 
     508                adm6996_apply_port_pvids(priv); 
     509        } 
     510} 
     511 
     512static int 
     513adm6996_reset_switch(struct switch_dev *dev) 
     514{ 
     515        struct adm6996_priv *priv = to_adm(dev); 
     516 
     517        dev_dbg (&priv->phydev->dev, "reset\n"); 
     518        mutex_lock(&priv->reg_mutex); 
     519        adm6996_perform_reset (priv); 
     520        mutex_unlock(&priv->reg_mutex); 
     521        return 0; 
     522} 
     523 
     524static struct switch_attr adm6996_globals[] = { 
     525        { 
     526         .type = SWITCH_TYPE_INT, 
     527         .name = "enable_vlan", 
     528         .description = "Enable VLANs", 
     529         .set = adm6996_set_enable_vlan, 
     530         .get = adm6996_get_enable_vlan, 
     531        }, 
     532#ifdef DEBUG 
     533        { 
     534         .type = SWITCH_TYPE_INT, 
     535         .name = "addr", 
     536         .description = 
     537         "Direct register access: set register address (0 - 1023)", 
     538         .set = adm6996_set_addr, 
     539         .get = adm6996_get_addr, 
     540         }, 
     541        { 
     542         .type = SWITCH_TYPE_INT, 
     543         .name = "data", 
     544         .description = 
     545         "Direct register access: read/write to register (0 - 65535)", 
     546         .set = adm6996_set_data, 
     547         .get = adm6996_get_data, 
     548         }, 
     549#endif /* def DEBUG */ 
     550}; 
     551 
     552static struct switch_attr adm6996_port[] = { 
     553}; 
     554 
     555static struct switch_attr adm6996_vlan[] = { 
     556        { 
     557         .type = SWITCH_TYPE_INT, 
     558         .name = "vid", 
     559         .description = "VLAN ID", 
     560         .set = adm6996_set_vid, 
     561         .get = adm6996_get_vid, 
     562         }, 
     563}; 
     564 
     565static const struct switch_dev_ops adm6996_ops = { 
     566        .attr_global = { 
     567                        .attr = adm6996_globals, 
     568                        .n_attr = ARRAY_SIZE(adm6996_globals), 
     569                        }, 
     570        .attr_port = { 
     571                      .attr = adm6996_port, 
     572                      .n_attr = ARRAY_SIZE(adm6996_port), 
     573                      }, 
     574        .attr_vlan = { 
     575                      .attr = adm6996_vlan, 
     576                      .n_attr = ARRAY_SIZE(adm6996_vlan), 
     577                      }, 
     578        .get_port_pvid = adm6996_get_pvid, 
     579        .set_port_pvid = adm6996_set_pvid, 
     580        .get_vlan_ports = adm6996_get_ports, 
     581        .set_vlan_ports = adm6996_set_ports, 
     582        .apply_config = adm6996_hw_apply, 
     583        .reset_switch = adm6996_reset_switch, 
     584}; 
    71585 
    72586static int adm6996_config_init(struct phy_device *pdev) 
    73587{ 
    74         int i; 
    75  
    76         printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name); 
     588        struct adm6996_priv *priv; 
     589        struct switch_dev *swdev; 
     590 
     591        int ret; 
     592        u16 test, old; 
     593 
    77594        pdev->supported = ADVERTISED_100baseT_Full; 
    78595        pdev->advertising = ADVERTISED_100baseT_Full; 
    79596 
    80         /* initialize port and vlan settings */ 
    81         for (i = 0; i < ADM_PHY_PORTS; i++) { 
    82                 w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT | 
    83                         ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0)); 
    84         } 
    85         w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU); 
    86  
    87         /* reset all ports */ 
    88         for (i = 0; i < ADM_PHY_PORTS; i++) { 
    89                 w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); 
    90         } 
    91  
    92         return 0; 
    93 } 
    94  
     597        if (pdev->addr != 0) { 
     598                pr_info ("%s: PHY overlaps ADM6996, providing fixed PHY 0x%x.\n" 
     599                                , pdev->attached_dev->name, pdev->addr); 
     600                return 0; 
     601        } 
     602 
     603        priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL); 
     604        if (priv == NULL) 
     605                return -ENOMEM; 
     606 
     607        mutex_init(&priv->reg_mutex); 
     608        priv->phydev = pdev; 
     609        priv->read = adm6996_read_mii_reg; 
     610        priv->write = adm6996_write_mii_reg; 
     611        pdev->priv = priv; 
     612 
     613        /* Detect type of chip */ 
     614        old = r16(pdev, ADM_VID_CHECK); 
     615        test = old ^ (1 << 12); 
     616        w16(pdev, ADM_VID_CHECK, test); 
     617        test ^= r16(pdev, ADM_VID_CHECK); 
     618        if (test & (1 << 12)) { 
     619                /*  
     620                 * Bit 12 of this register is read-only.  
     621                 * This is the FC model.  
     622                 */ 
     623                priv->model = ADM6996FC; 
     624        } else { 
     625                /* Bit 12 is read-write. This is the M model. */ 
     626                priv->model = ADM6996M; 
     627                w16(pdev, ADM_VID_CHECK, old); 
     628        } 
     629 
     630        swdev = &priv->dev; 
     631        swdev->name = (adm6996_model_name[priv->model]); 
     632        swdev->cpu_port = ADM_CPU_PORT; 
     633        swdev->ports = ADM_NUM_PORTS; 
     634        swdev->vlans = ADM_NUM_VLANS; 
     635        swdev->ops = &adm6996_ops; 
     636 
     637        pr_info ("%s: %s model PHY found.\n", pdev->attached_dev->name, 
     638                        swdev->name); 
     639 
     640        mutex_lock(&priv->reg_mutex); 
     641        adm6996_perform_reset (priv); 
     642        mutex_unlock(&priv->reg_mutex); 
     643 
     644        if (priv->model == ADM6996M) { 
     645                if ((ret = register_switch(swdev, pdev->attached_dev)) < 0) { 
     646                        kfree(priv); 
     647                        return ret; 
     648                } 
     649        } 
     650 
     651        return 0; 
     652} 
     653 
     654/* 
     655 * Warning: phydev->priv is NULL if phydev->addr != 0 
     656 */ 
    95657static int adm6996_read_status(struct phy_device *phydev) 
    96658{ 
     
    101663} 
    102664 
     665/* 
     666 * Warning: phydev->priv is NULL if phydev->addr != 0 
     667 */ 
    103668static int adm6996_config_aneg(struct phy_device *phydev) 
    104669{ 
     
    110675        struct mii_bus *bus = dev->bus; 
    111676        u16 reg; 
     677 
     678        /* Our custom registers are at PHY addresses 0-10. Claim those. */ 
     679        if (dev->addr > 10) 
     680                return 0; 
    112681 
    113682        /* look for the switch on the bus */ 
     
    121690 
    122691        dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; 
     692 
    123693        return 0; 
    124694} 
     
    126696static int adm6996_probe(struct phy_device *pdev) 
    127697{ 
    128         struct adm6996_priv *priv; 
    129  
    130         priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL); 
    131         if (priv == NULL) 
    132                 return -ENOMEM; 
    133  
    134         priv->read = adm6996_read_mii_reg; 
    135         priv->write = adm6996_write_mii_reg; 
    136         pdev->priv = priv; 
    137698        return 0; 
    138699} 
     
    140701static void adm6996_remove(struct phy_device *pdev) 
    141702{ 
    142         kfree(pdev->priv); 
     703        struct adm6996_priv *priv = phy_to_adm(pdev); 
     704 
     705        if (priv != NULL && priv->model == ADM6996M) 
     706                unregister_switch(&priv->dev); 
     707 
     708        kfree(priv); 
    143709} 
    144710 
  • trunk/target/linux/generic/files/drivers/net/phy/adm6996.h

    r21952 r26865  
    33 * 
    44 * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> 
     5 * Copyright (c) 2010,2011 Peter Lebbing <peter@digitalbrains.com> 
    56 * 
    67 * This program is free software; you can redistribute  it and/or modify it 
     
    1112#define __ADM6996_H 
    1213 
    13 #define ADM_PHY_PORTS   5 
     14/* 
     15 * ADM_PHY_PORTS: Number of ports with a PHY. 
     16 * We only control ports 0 to 3, because if 4 is connected, it is most likely 
     17 * not connected to the switch but to a separate MII and MAC for the WAN port. 
     18 */ 
     19#define ADM_PHY_PORTS   4 
     20#define ADM_NUM_PORTS   6 
    1421#define ADM_CPU_PORT    5 
    15 #define ADM_WAN_PORT    0 /* FIXME: dynamic ? */ 
     22 
     23#define ADM_NUM_VLANS 16 
     24#define ADM_VLAN_MAX_ID 4094 
    1625 
    1726enum admreg { 
     
    2332                ADM_P4_CFG              = ADM_EEPROM_BASE + 8, 
    2433                ADM_P5_CFG              = ADM_EEPROM_BASE + 9, 
     34                ADM_SYSC0               = ADM_EEPROM_BASE + 0xa, 
     35                ADM_VLAN_PRIOMAP        = ADM_EEPROM_BASE + 0xe, 
     36                ADM_SYSC3               = ADM_EEPROM_BASE + 0x11, 
     37                /* Input Force No Tag Enable */ 
     38                ADM_IFNTE               = ADM_EEPROM_BASE + 0x20, 
     39                ADM_VID_CHECK           = ADM_EEPROM_BASE + 0x26, 
     40                ADM_P0_PVID             = ADM_EEPROM_BASE + 0x28, 
     41                ADM_P1_PVID             = ADM_EEPROM_BASE + 0x29, 
     42                /* Output Tag Bypass Enable and P2 PVID */ 
     43                ADM_OTBE_P2_PVID        = ADM_EEPROM_BASE + 0x2a, 
     44                ADM_P3_P4_PVID          = ADM_EEPROM_BASE + 0x2b, 
     45                ADM_P5_PVID             = ADM_EEPROM_BASE + 0x2c, 
    2546        ADM_EEPROM_EXT_BASE     = 0x40, 
     47#define ADM_VLAN_FILT_L(n) (ADM_EEPROM_EXT_BASE + 2 * (n)) 
     48#define ADM_VLAN_FILT_H(n) (ADM_EEPROM_EXT_BASE + 1 + 2 * (n)) 
    2649        ADM_COUNTER_BASE        = 0xa0, 
    2750                ADM_SIG0                = ADM_COUNTER_BASE + 0, 
     
    3255 
    3356/* Chip identification patterns */ 
    34 #define ADM_SIG0_MASK   0xfff0 
    35 #define ADM_SIG0_VAL    0x1020 
     57#define ADM_SIG0_MASK   0xffff 
     58#define ADM_SIG0_VAL    0x1023 
    3659#define ADM_SIG1_MASK   0xffff 
    3760#define ADM_SIG1_VAL    0x0007 
     
    85108}; 
    86109 
    87 #define ADM_PORTCFG_PPID(N) ((n & 0x3) << 8) 
     110#define ADM_PORTCFG_PPID(n) ((n & 0x3) << 8) 
    88111#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) 
     112#define ADM_PORTCFG_PVID_MASK (0xf << 10) 
     113 
     114#define ADM_IFNTE_MASK (0x3f << 9) 
     115#define ADM_VID_CHECK_MASK (0x3f << 6) 
     116 
     117#define ADM_P0_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) 
     118#define ADM_P1_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) 
     119#define ADM_P2_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) 
     120#define ADM_P3_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) 
     121#define ADM_P4_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 8) 
     122#define ADM_P5_PVID_VAL(n) ((((n) & 0xff0) >> 4) << 0) 
     123#define ADM_P2_PVID_MASK 0xff 
     124 
     125#define ADM_OTBE(n) (((n) & 0x3f) << 8) 
     126#define ADM_OTBE_MASK (0x3f << 8) 
     127 
     128/* ADM_SYSC0 */ 
     129enum { 
     130        ADM_NTTE        = (1 << 2),     /* New Tag Transmit Enable */ 
     131        ADM_RVID1       = (1 << 8)      /* Replace VLAN ID 1 */ 
     132}; 
     133 
     134/* Tag Based VLAN in ADM_SYSC3 */ 
     135#define ADM_TBV (1 << 5) 
    89136 
    90137static const u8 adm_portcfg[] = { 
     
    97144}; 
    98145 
     146/* Fields in ADM_VLAN_FILT_L(x) */ 
     147#define ADM_VLAN_FILT_FID(n) (((n) & 0xf) << 12) 
     148#define ADM_VLAN_FILT_TAGGED(n) (((n) & 0x3f) << 6) 
     149#define ADM_VLAN_FILT_MEMBER(n) (((n) & 0x3f) << 0) 
     150#define ADM_VLAN_FILT_MEMBER_MASK 0x3f 
     151/* Fields in ADM_VLAN_FILT_H(x) */ 
     152#define ADM_VLAN_FILT_VALID (1 << 15) 
     153#define ADM_VLAN_FILT_VID(n) (((n) & 0xfff) << 0) 
     154 
     155 
    99156/* 
    100157 * Split the register address in phy id and register 
  • trunk/target/linux/generic/patches-2.6.30/620-phy_adm6996.patch

    r21952 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -82,6 +82,11 @@ config LSI_ET1011C_PHY 
     3@@ -82,6 +82,13 @@ config LSI_ET1011C_PHY 
    44        ---help--- 
    55          Supports the LSI ET1011C PHY. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.31/620-phy_adm6996.patch

    r21952 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -82,6 +82,11 @@ config LSI_ET1011C_PHY 
     3@@ -82,6 +82,13 @@ config LSI_ET1011C_PHY 
    44        ---help--- 
    55          Supports the LSI ET1011C PHY. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.32/620-phy_adm6996.patch

    r21952 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -88,6 +88,11 @@ config LSI_ET1011C_PHY 
     3@@ -88,6 +88,13 @@ config LSI_ET1011C_PHY 
    44        ---help--- 
    55          Supports the LSI ET1011C PHY. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.36/620-phy_adm6996.patch

    r21952 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -93,6 +93,11 @@ config MICREL_PHY 
     3@@ -93,6 +93,13 @@ config MICREL_PHY 
    44        ---help--- 
    55          Supports the KSZ9021, VSC8201, KS8001 PHYs. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.37/720-phy_adm6996.patch

    r26692 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -98,6 +98,11 @@ config MICREL_PHY 
     3@@ -98,6 +98,13 @@ config MICREL_PHY 
    44        ---help--- 
    55          Supports the KSZ9021, VSC8201, KS8001 PHYs. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.38/720-phy_adm6996.patch

    r26690 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -98,6 +98,11 @@ config MICREL_PHY 
     3@@ -98,6 +98,13 @@ config MICREL_PHY 
    44        ---help--- 
    55          Supports the KSZ9021, VSC8201, KS8001 PHYs. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
  • trunk/target/linux/generic/patches-2.6.39/720-phy_adm6996.patch

    r26691 r26865  
    11--- a/drivers/net/phy/Kconfig 
    22+++ b/drivers/net/phy/Kconfig 
    3 @@ -97,6 +97,11 @@ config MICREL_PHY 
     3@@ -97,6 +97,13 @@ config MICREL_PHY 
    44        ---help--- 
    55          Supports the KSZ9021, VSC8201, KS8001 PHYs. 
     
    77+config ADM6996_PHY 
    88+       tristate "Driver for ADM6996 switches" 
     9+       select SWCONFIG 
    910+       ---help--- 
    10 +         Currently supports the ADM6996F switch 
     11+         Currently supports the ADM6996FC and ADM6996M switches. 
     12+         Support for FC is very limited. 
    1113+ 
    1214 config FIXED_PHY 
Note: See TracChangeset for help on using the changeset viewer.