ar8216: introduce enable_eee swconfig attribute to control 802.3az EEE per port
[openwrt/staging/dedeckeh.git] / target / linux / generic / files / drivers / net / phy / ar8327.c
index f6d07c19829b1355860b8faa1378d7e390b998f4..0971f80d50f2fd16b64cf9aa858f5352b00f2f34 100644 (file)
@@ -30,7 +30,6 @@
 #include "ar8327.h"
 
 extern const struct ar8xxx_mib_desc ar8236_mibs[39];
-extern const struct switch_attr ar8xxx_sw_attr_port[2];
 extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
 
 static u32
@@ -651,7 +650,9 @@ ar8327_cleanup(struct ar8xxx_priv *priv)
 static void
 ar8327_init_globals(struct ar8xxx_priv *priv)
 {
+       struct ar8327_data *data = priv->chip_data;
        u32 t;
+       int i;
 
        /* enable CPU port and disable mirror port */
        t = AR8327_FWD_CTRL0_CPU_PORT_EN |
@@ -672,14 +673,9 @@ ar8327_init_globals(struct ar8xxx_priv *priv)
        ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
                       AR8327_MODULE_EN_MIB);
 
-       /* Disable EEE on all ports due to stability issues */
-       t = ar8xxx_read(priv, AR8327_REG_EEE_CTRL);
-       t |= AR8327_EEE_CTRL_DISABLE_PHY(0) |
-            AR8327_EEE_CTRL_DISABLE_PHY(1) |
-            AR8327_EEE_CTRL_DISABLE_PHY(2) |
-            AR8327_EEE_CTRL_DISABLE_PHY(3) |
-            AR8327_EEE_CTRL_DISABLE_PHY(4);
-       ar8xxx_write(priv, AR8327_REG_EEE_CTRL, t);
+       /* Disable EEE on all phy's due to stability issues */
+       for (i = 0; i < AR8XXX_NUM_PHYS; i++)
+               data->eee[i] = false;
 }
 
 static void
@@ -892,6 +888,73 @@ ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
                           AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
 }
 
+static int
+ar8327_sw_set_eee(struct switch_dev *dev,
+                 const struct switch_attr *attr,
+                 struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       struct ar8327_data *data = priv->chip_data;
+       int port = val->port_vlan;
+       int phy;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+       if (port == 0 || port == 6)
+               return -EOPNOTSUPP;
+
+       phy = port - 1;
+
+       data->eee[phy] = !!(val->value.i);
+
+       return 0;
+}
+
+static int
+ar8327_sw_get_eee(struct switch_dev *dev,
+                 const struct switch_attr *attr,
+                 struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8327_data *data = priv->chip_data;
+       int port = val->port_vlan;
+       int phy;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+       if (port == 0 || port == 6)
+               return -EOPNOTSUPP;
+
+       phy = port - 1;
+
+       val->value.i = data->eee[phy];
+
+       return 0;
+}
+
+static int
+ar8327_sw_hw_apply(struct switch_dev *dev)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8327_data *data = priv->chip_data;
+       int ret, i;
+
+       ret = ar8xxx_sw_hw_apply(dev);
+       if (ret)
+               return ret;
+
+       for (i=0; i < AR8XXX_NUM_PHYS; i++) {
+               if (data->eee[i])
+                       ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL,
+                              AR8327_EEE_CTRL_DISABLE_PHY(i));
+               else
+                       ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL,
+                              AR8327_EEE_CTRL_DISABLE_PHY(i));
+       }
+
+       return 0;
+}
+
 static const struct switch_attr ar8327_sw_attr_globals[] = {
        {
                .type = SWITCH_TYPE_INT,
@@ -941,14 +1004,38 @@ static const struct switch_attr ar8327_sw_attr_globals[] = {
        },
 };
 
+static const struct switch_attr ar8327_sw_attr_port[] = {
+       {
+               .type = SWITCH_TYPE_NOVAL,
+               .name = "reset_mib",
+               .description = "Reset single port MIB counters",
+               .set = ar8xxx_sw_set_port_reset_mib,
+       },
+       {
+               .type = SWITCH_TYPE_STRING,
+               .name = "mib",
+               .description = "Get port's MIB counters",
+               .set = NULL,
+               .get = ar8xxx_sw_get_port_mib,
+       },
+       {
+               .type = SWITCH_TYPE_INT,
+               .name = "enable_eee",
+               .description = "Enable EEE PHY sleep mode",
+               .set = ar8327_sw_set_eee,
+               .get = ar8327_sw_get_eee,
+               .max = 1,
+       },
+};
+
 static const struct switch_dev_ops ar8327_sw_ops = {
        .attr_global = {
                .attr = ar8327_sw_attr_globals,
                .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
        },
        .attr_port = {
-               .attr = ar8xxx_sw_attr_port,
-               .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
+               .attr = ar8327_sw_attr_port,
+               .n_attr = ARRAY_SIZE(ar8327_sw_attr_port),
        },
        .attr_vlan = {
                .attr = ar8xxx_sw_attr_vlan,
@@ -958,7 +1045,7 @@ static const struct switch_dev_ops ar8327_sw_ops = {
        .set_port_pvid = ar8xxx_sw_set_pvid,
        .get_vlan_ports = ar8327_sw_get_ports,
        .set_vlan_ports = ar8327_sw_set_ports,
-       .apply_config = ar8xxx_sw_hw_apply,
+       .apply_config = ar8327_sw_hw_apply,
        .reset_switch = ar8xxx_sw_reset_switch,
        .get_port_link = ar8xxx_sw_get_port_link,
 };
@@ -987,6 +1074,7 @@ const struct ar8xxx_chip ar8327_chip = {
        .vtu_load_vlan = ar8327_vtu_load_vlan,
        .phy_fixup = ar8327_phy_fixup,
        .set_mirror_regs = ar8327_set_mirror_regs,
+       .sw_hw_apply = ar8327_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,
@@ -1017,6 +1105,7 @@ const struct ar8xxx_chip ar8337_chip = {
        .vtu_load_vlan = ar8327_vtu_load_vlan,
        .phy_fixup = ar8327_phy_fixup,
        .set_mirror_regs = ar8327_set_mirror_regs,
+       .sw_hw_apply = ar8327_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,