Rebased from upstream / out of band repository.
[librecmc/librecmc.git] / target / linux / generic / pending-4.9 / 734-net-phy-at803x-allow-to-configure-via-pdata.patch
1 From: Gabor Juhos <juhosg@openwrt.org>
2 Subject: net: phy: allow to configure AR803x PHYs via platform data
3
4 Add a patch for the at803x phy driver, in order to be able
5 to configure some register settings via platform data.
6
7 Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
8 ---
9  drivers/net/phy/at803x.c                 | 56 ++++++++++++++++++++++++++++++++
10  include/linux/platform_data/phy-at803x.h | 11 +++++++
11  2 files changed, 67 insertions(+)
12  create mode 100644 include/linux/platform_data/phy-at803x.h
13
14 --- a/drivers/net/phy/at803x.c
15 +++ b/drivers/net/phy/at803x.c
16 @@ -12,12 +12,14 @@
17   */
18  
19  #include <linux/phy.h>
20 +#include <linux/mdio.h>
21  #include <linux/module.h>
22  #include <linux/string.h>
23  #include <linux/netdevice.h>
24  #include <linux/etherdevice.h>
25  #include <linux/of_gpio.h>
26  #include <linux/gpio/consumer.h>
27 +#include <linux/platform_data/phy-at803x.h>
28  
29  #define AT803X_INTR_ENABLE                     0x12
30  #define AT803X_INTR_ENABLE_AUTONEG_ERR         BIT(15)
31 @@ -45,6 +47,11 @@
32  #define AT803X_REG_CHIP_CONFIG                 0x1f
33  #define AT803X_BT_BX_REG_SEL                   0x8000
34  
35 +#define AT803X_PCS_SMART_EEE_CTRL3                     0x805D
36 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK   0x3
37 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT  12
38 +#define AT803X_SMART_EEE_CTRL3_LPI_EN                  BIT(8)
39 +
40  #define AT803X_DEBUG_ADDR                      0x1D
41  #define AT803X_DEBUG_DATA                      0x1E
42  
43 @@ -72,6 +79,7 @@ MODULE_LICENSE("GPL");
44  struct at803x_priv {
45         bool phy_reset:1;
46         struct gpio_desc *gpiod_reset;
47 +       int prev_speed;
48  };
49  
50  struct at803x_context {
51 @@ -276,8 +284,16 @@ does_not_require_reset_workaround:
52         return 0;
53  }
54  
55 +static void at803x_disable_smarteee(struct phy_device *phydev)
56 +{
57 +       phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
58 +               1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
59 +       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
60 +}
61 +
62  static int at803x_config_init(struct phy_device *phydev)
63  {
64 +       struct at803x_platform_data *pdata;
65         int ret;
66  
67         ret = genphy_config_init(phydev);
68 @@ -298,6 +314,26 @@ static int at803x_config_init(struct phy
69                         return ret;
70         }
71  
72 +       pdata = dev_get_platdata(&phydev->mdio.dev);
73 +       if (pdata) {
74 +               if (pdata->disable_smarteee)
75 +                       at803x_disable_smarteee(phydev);
76 +
77 +               if (pdata->enable_rgmii_rx_delay)
78 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
79 +                               AT803X_DEBUG_RX_CLK_DLY_EN);
80 +               else
81 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
82 +                               AT803X_DEBUG_RX_CLK_DLY_EN, 0);
83 +
84 +               if (pdata->enable_rgmii_tx_delay)
85 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
86 +                               AT803X_DEBUG_TX_CLK_DLY_EN);
87 +               else
88 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
89 +                               AT803X_DEBUG_TX_CLK_DLY_EN, 0);
90 +       }
91 +
92         return 0;
93  }
94  
95 @@ -335,6 +371,8 @@ static int at803x_config_intr(struct phy
96  static void at803x_link_change_notify(struct phy_device *phydev)
97  {
98         struct at803x_priv *priv = phydev->priv;
99 +       struct at803x_platform_data *pdata;
100 +       pdata = dev_get_platdata(&phydev->mdio.dev);
101  
102         /*
103          * Conduct a hardware reset for AT8030/2 every time a link loss is
104 @@ -363,6 +401,24 @@ static void at803x_link_change_notify(st
105         } else {
106                 priv->phy_reset = false;
107         }
108 +       if (pdata && pdata->fixup_rgmii_tx_delay &&
109 +           phydev->speed != priv->prev_speed) {
110 +               switch (phydev->speed) {
111 +               case SPEED_10:
112 +               case SPEED_100:
113 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
114 +                               AT803X_DEBUG_TX_CLK_DLY_EN);
115 +                       break;
116 +               case SPEED_1000:
117 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
118 +                               AT803X_DEBUG_TX_CLK_DLY_EN, 0);
119 +                       break;
120 +               default:
121 +                       break;
122 +               }
123 +
124 +               priv->prev_speed = phydev->speed;
125 +       }
126  }
127  
128  static int at803x_aneg_done(struct phy_device *phydev)
129 --- /dev/null
130 +++ b/include/linux/platform_data/phy-at803x.h
131 @@ -0,0 +1,11 @@
132 +#ifndef _PHY_AT803X_PDATA_H
133 +#define _PHY_AT803X_PDATA_H
134 +
135 +struct at803x_platform_data {
136 +       int disable_smarteee:1;
137 +       int enable_rgmii_tx_delay:1;
138 +       int enable_rgmii_rx_delay:1;
139 +       int fixup_rgmii_tx_delay:1;
140 +};
141 +
142 +#endif /* _PHY_AT803X_PDATA_H */