generic: ar8216: add read_port_status field to ar8xxx_chip
[openwrt/svn-archive/archive.git] / target / linux / generic / files / drivers / net / phy / ar8216.c
index 038a086bd94a96788a8801d2b2e19e84bd99ed3d..019d527b711c347035885202e11d077269ff8f2f 100644 (file)
 #define AR8X16_MAX_VLANS       128
 #define AR8X16_PROBE_RETRIES   10
 
+struct ar8216_priv;
+
+#define AR8XXX_CAP_GIGE                BIT(0)
+
 struct ar8xxx_chip {
+       unsigned long caps;
+
+       int (*hw_init)(struct ar8216_priv *priv);
+       void (*init_globals)(struct ar8216_priv *priv);
+       void (*init_port)(struct ar8216_priv *priv, int port);
+       void (*setup_port)(struct ar8216_priv *priv, int port, u32 egress,
+                          u32 ingress, u32 members, u32 pvid);
+       u32 (*read_port_status)(struct ar8216_priv *priv, int port);
+       int (*atu_flush)(struct ar8216_priv *priv);
+       void (*vtu_flush)(struct ar8216_priv *priv);
+       void (*vtu_load_vlan)(struct ar8216_priv *priv, u32 vid, u32 port_mask);
 };
 
 struct ar8216_priv {
@@ -65,6 +80,11 @@ struct ar8216_priv {
 
 #define to_ar8216(_dev) container_of(_dev, struct ar8216_priv, dev)
 
+static inline bool ar8xxx_has_gige(struct ar8216_priv *priv)
+{
+       return priv->chip->caps & AR8XXX_CAP_GIGE;
+}
+
 static inline void
 split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
 {
@@ -158,7 +178,7 @@ ar8216_read_port_link(struct ar8216_priv *priv, int port,
 
        memset(link, '\0', sizeof(*link));
 
-       status = priv->read(priv, AR8216_REG_PORT_STATUS(port));
+       status = priv->chip->read_port_status(priv, port);
 
        link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
        if (link->aneg) {
@@ -475,6 +495,39 @@ ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val)
        priv->write(priv, AR8216_REG_VTU, op);
 }
 
+static void
+ar8216_vtu_flush(struct ar8216_priv *priv)
+{
+       ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
+}
+
+static void
+ar8216_vtu_load_vlan(struct ar8216_priv *priv, u32 vid, u32 port_mask)
+{
+       u32 op;
+
+       op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S);
+       ar8216_vtu_op(priv, op, port_mask);
+}
+
+static int
+ar8216_atu_flush(struct ar8216_priv *priv)
+{
+       int ret;
+
+       ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0);
+       if (!ret)
+               priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
+
+       return ret;
+}
+
+static u32
+ar8216_read_port_status(struct ar8216_priv *priv, int port)
+{
+       return priv->read(priv, AR8216_REG_PORT_STATUS(port));
+}
+
 static void
 ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress,
                  u32 members, u32 pvid)
@@ -534,7 +587,7 @@ ar8216_hw_apply(struct switch_dev *dev)
 
        mutex_lock(&priv->reg_mutex);
        /* flush all vlan translation unit entries */
-       ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
+       priv->chip->vtu_flush(priv);
 
        memset(portmask, 0, sizeof(portmask));
        if (!priv->init) {
@@ -552,10 +605,8 @@ ar8216_hw_apply(struct switch_dev *dev)
                                        portmask[i] |= vp & ~mask;
                        }
 
-                       ar8216_vtu_op(priv,
-                               AR8216_VTU_OP_LOAD |
-                               (priv->vlan_id[j] << AR8216_VTU_VID_S),
-                               priv->vlan_table[j]);
+                       priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
+                                                priv->vlan_table[j]);
                }
        } else {
                /* vlan disabled:
@@ -587,12 +638,8 @@ ar8216_hw_apply(struct switch_dev *dev)
                        ingress = AR8216_IN_PORT_ONLY;
                }
 
-               if (priv->chip_type == AR8236)
-                       ar8236_setup_port(priv, i, egress, ingress, portmask[i],
-                                         pvid);
-               else
-                       ar8216_setup_port(priv, i, egress, ingress, portmask[i],
-                                         pvid);
+               priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
+                                      pvid);
        }
        mutex_unlock(&priv->reg_mutex);
        return 0;
@@ -690,28 +737,33 @@ out:
 static void
 ar8216_init_globals(struct ar8216_priv *priv)
 {
-       switch (priv->chip_type) {
-       case AR8216:
-               /* standard atheros magic */
-               priv->write(priv, 0x38, 0xc000050e);
+       /* standard atheros magic */
+       priv->write(priv, 0x38, 0xc000050e);
 
-               ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
-                          AR8216_GCTRL_MTU, 1518 + 8 + 2);
-               break;
-       case AR8316:
-               /* standard atheros magic */
-               priv->write(priv, 0x38, 0xc000050e);
-
-               /* enable cpu port to receive multicast and broadcast frames */
-               priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
-
-               /* fall through */
-       case AR8236:
-               /* enable jumbo frames */
-               ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
-                          AR8316_GCTRL_MTU, 9018 + 8 + 2);
-               break;
-       }
+       ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+                  AR8216_GCTRL_MTU, 1518 + 8 + 2);
+}
+
+static void
+ar8236_init_globals(struct ar8216_priv *priv)
+{
+       /* enable jumbo frames */
+       ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+                  AR8316_GCTRL_MTU, 9018 + 8 + 2);
+}
+
+static void
+ar8316_init_globals(struct ar8216_priv *priv)
+{
+       /* standard atheros magic */
+       priv->write(priv, 0x38, 0xc000050e);
+
+       /* enable cpu port to receive multicast and broadcast frames */
+       priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
+
+       /* enable jumbo frames */
+       ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+                  AR8316_GCTRL_MTU, 9018 + 8 + 2);
 }
 
 static void
@@ -727,8 +779,8 @@ ar8216_init_port(struct ar8216_priv *priv, int port)
        if (port == AR8216_PORT_CPU) {
                priv->write(priv, AR8216_REG_PORT_STATUS(port),
                        AR8216_PORT_STATUS_LINK_UP |
-                       ((priv->chip_type == AR8316) ?
-                               AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
+                       ar8xxx_has_gige(priv) ? AR8216_PORT_SPEED_1000M :
+                                               AR8216_PORT_SPEED_100M |
                        AR8216_PORT_STATUS_TXMAC |
                        AR8216_PORT_STATUS_RXMAC |
                        ((priv->chip_type == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) |
@@ -741,12 +793,37 @@ ar8216_init_port(struct ar8216_priv *priv, int port)
 }
 
 static const struct ar8xxx_chip ar8216_chip = {
+       .hw_init = ar8216_hw_init,
+       .init_globals = ar8216_init_globals,
+       .init_port = ar8216_init_port,
+       .setup_port = ar8216_setup_port,
+       .read_port_status = ar8216_read_port_status,
+       .atu_flush = ar8216_atu_flush,
+       .vtu_flush = ar8216_vtu_flush,
+       .vtu_load_vlan = ar8216_vtu_load_vlan,
 };
 
 static const struct ar8xxx_chip ar8236_chip = {
+       .hw_init = ar8236_hw_init,
+       .init_globals = ar8236_init_globals,
+       .init_port = ar8216_init_port,
+       .setup_port = ar8236_setup_port,
+       .read_port_status = ar8216_read_port_status,
+       .atu_flush = ar8216_atu_flush,
+       .vtu_flush = ar8216_vtu_flush,
+       .vtu_load_vlan = ar8216_vtu_load_vlan,
 };
 
 static const struct ar8xxx_chip ar8316_chip = {
+       .caps = AR8XXX_CAP_GIGE,
+       .hw_init = ar8316_hw_init,
+       .init_globals = ar8316_init_globals,
+       .init_port = ar8216_init_port,
+       .setup_port = ar8216_setup_port,
+       .read_port_status = ar8216_read_port_status,
+       .atu_flush = ar8216_atu_flush,
+       .vtu_flush = ar8216_vtu_flush,
+       .vtu_load_vlan = ar8216_vtu_load_vlan,
 };
 
 static int
@@ -764,7 +841,7 @@ ar8216_reset_switch(struct switch_dev *dev)
 
        /* Configure all ports */
        for (i = 0; i < AR8216_NUM_PORTS; i++)
-               ar8216_init_port(priv, i);
+               priv->chip->init_port(priv, i);
 
        ar8216_init_globals(priv);
        mutex_unlock(&priv->reg_mutex);
@@ -869,10 +946,12 @@ ar8216_config_init(struct phy_device *pdev)
                goto err_free_priv;
 
        if (pdev->addr != 0) {
-               if (priv->chip_type == AR8316) {
+               if (ar8xxx_has_gige(priv)) {
                        pdev->supported |= SUPPORTED_1000baseT_Full;
                        pdev->advertising |= ADVERTISED_1000baseT_Full;
+               }
 
+               if (priv->chip_type == AR8316) {
                        /* check if we're attaching to the switch twice */
                        pdev = pdev->bus->phy_map[0];
                        if (!pdev) {
@@ -905,8 +984,10 @@ ar8216_config_init(struct phy_device *pdev)
        printk(KERN_INFO "%s: AR%d switch driver attached.\n",
                pdev->attached_dev->name, priv->chip_type);
 
-       pdev->supported = priv->chip_type == AR8316 ?
-               SUPPORTED_1000baseT_Full : SUPPORTED_100baseT_Full;
+       if (ar8xxx_has_gige(priv))
+               pdev->supported = SUPPORTED_1000baseT_Full;
+       else
+               pdev->supported = SUPPORTED_100baseT_Full;
        pdev->advertising = pdev->supported;
 
        mutex_init(&priv->reg_mutex);
@@ -943,14 +1024,7 @@ ar8216_config_init(struct phy_device *pdev)
 
        priv->init = true;
 
-       ret = 0;
-       if (priv->chip_type == AR8216)
-               ret = ar8216_hw_init(priv);
-       else if (priv->chip_type == AR8236)
-               ret = ar8236_hw_init(priv);
-       else if (priv->chip_type == AR8316)
-               ret = ar8316_hw_init(priv);
-
+       ret = priv->chip->hw_init(priv);
        if (ret)
                goto err_free_priv;
 
@@ -1012,9 +1086,7 @@ ar8216_read_status(struct phy_device *phydev)
 
        /* flush the address translation unit */
        mutex_lock(&priv->reg_mutex);
-       ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0);
-       if (!ret)
-               priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
+       ret = priv->chip->atu_flush(priv);
        mutex_unlock(&priv->reg_mutex);
 
        phydev->state = PHY_RUNNING;