ar8216: add 802.3az EEE info to swconfig get_link attribute
[openwrt/openwrt.git] / target / linux / generic / files / drivers / net / phy / ar8327.c
index f6d07c19829b1355860b8faa1378d7e390b998f4..c0262d71455a5db75d87ee27dd42d886a4bc5d9e 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/of_device.h>
 #include <linux/leds.h>
+#include <linux/mdio.h>
 
 #include "ar8216.h"
 #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 +651,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 +674,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
@@ -716,6 +713,27 @@ ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
        return ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port));
 }
 
+static u32
+ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port)
+{
+       int phy;
+       u16 t;
+
+       if (port >= priv->dev.ports)
+               return 0;
+
+       if (port == 0 || port == 6)
+               return 0;
+
+       phy = port - 1;
+
+       /* EEE Ability Auto-negotiation Result */
+       ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x8000);
+       t = ar8xxx_phy_mmd_read(priv, phy, 0x4007);
+
+       return mmd_eee_adv_to_ethtool_adv_t(t);
+}
+
 static int
 ar8327_atu_flush(struct ar8xxx_priv *priv)
 {
@@ -892,6 +910,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 +1026,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 +1067,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,
 };
@@ -982,11 +1091,13 @@ const struct ar8xxx_chip ar8327_chip = {
        .init_port = ar8327_init_port,
        .setup_port = ar8327_setup_port,
        .read_port_status = ar8327_read_port_status,
+       .read_port_eee_status = ar8327_read_port_eee_status,
        .atu_flush = ar8327_atu_flush,
        .vtu_flush = ar8327_vtu_flush,
        .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,
@@ -1012,11 +1123,13 @@ const struct ar8xxx_chip ar8337_chip = {
        .init_port = ar8327_init_port,
        .setup_port = ar8327_setup_port,
        .read_port_status = ar8327_read_port_status,
+       .read_port_eee_status = ar8327_read_port_eee_status,
        .atu_flush = ar8327_atu_flush,
        .vtu_flush = ar8327_vtu_flush,
        .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,