20325f564d4f51a686a26f6190f9b1c9377afa0c
[openwrt/staging/dedeckeh.git] /
1 From 272833b9b3b3969be7a91839121d86662c8c4253 Mon Sep 17 00:00:00 2001
2 From: Ansuel Smith <ansuelsmth@gmail.com>
3 Date: Fri, 14 May 2021 23:00:15 +0200
4 Subject: [PATCH] net: phy: add support for qca8k switch internal PHY in at803x
5
6 Since the at803x share the same regs, it's assumed they are based on the
7 same implementation. Make it part of the at803x PHY driver to skip
8 having redudant code.
9 Add initial support for qca8k internal PHYs. The internal PHYs requires
10 special mmd and debug values to be set based on the switch revision
11 passwd using the dev_flags. Supports output of idle, receive and eee_wake
12 errors stats.
13 Some debug values sets can't be translated as the documentation lacks any
14 reference about them.
15
16 Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
17 Signed-off-by: David S. Miller <davem@davemloft.net>
18 ---
19 drivers/net/phy/Kconfig | 5 +-
20 drivers/net/phy/at803x.c | 132 ++++++++++++++++++++++++++++++++++++++-
21 2 files changed, 134 insertions(+), 3 deletions(-)
22
23 --- a/drivers/net/phy/Kconfig
24 +++ b/drivers/net/phy/Kconfig
25 @@ -235,10 +235,11 @@ config NXP_TJA11XX_PHY
26 Currently supports the NXP TJA1100 and TJA1101 PHY.
27
28 config AT803X_PHY
29 - tristate "Qualcomm Atheros AR803X PHYs"
30 + tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
31 depends on REGULATOR
32 help
33 - Currently supports the AR8030, AR8031, AR8033 and AR8035 model
34 + Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
35 + QCA8337(Internal qca8k PHY) model
36
37 config QSEMI_PHY
38 tristate "Quality Semiconductor PHYs"
39 --- a/drivers/net/phy/at803x.c
40 +++ b/drivers/net/phy/at803x.c
41 @@ -92,10 +92,16 @@
42 #define AT803X_DEBUG_REG_5 0x05
43 #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
44
45 +#define AT803X_DEBUG_REG_3C 0x3C
46 +
47 +#define AT803X_DEBUG_REG_3D 0x3D
48 +
49 #define AT803X_DEBUG_REG_1F 0x1F
50 #define AT803X_DEBUG_PLL_ON BIT(2)
51 #define AT803X_DEBUG_RGMII_1V8 BIT(3)
52
53 +#define MDIO_AZ_DEBUG 0x800D
54 +
55 /* AT803x supports either the XTAL input pad, an internal PLL or the
56 * DSP as clock reference for the clock output pad. The XTAL reference
57 * is only used for 25 MHz output, all other frequencies need the PLL.
58 @@ -142,10 +148,34 @@
59 #define AT803X_PAGE_FIBER 0
60 #define AT803X_PAGE_COPPER 1
61
62 +#define QCA8327_PHY_ID 0x004dd034
63 +#define QCA8337_PHY_ID 0x004dd036
64 +#define QCA8K_PHY_ID_MASK 0xffffffff
65 +
66 +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
67 +
68 MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver");
69 MODULE_AUTHOR("Matus Ujhelyi");
70 MODULE_LICENSE("GPL");
71
72 +enum stat_access_type {
73 + PHY,
74 + MMD
75 +};
76 +
77 +struct at803x_hw_stat {
78 + const char *string;
79 + u8 reg;
80 + u32 mask;
81 + enum stat_access_type access_type;
82 +};
83 +
84 +static struct at803x_hw_stat at803x_hw_stats[] = {
85 + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
86 + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
87 + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
88 +};
89 +
90 struct at803x_priv {
91 int flags;
92 #define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */
93 @@ -154,6 +184,7 @@ struct at803x_priv {
94 struct regulator_dev *vddio_rdev;
95 struct regulator_dev *vddh_rdev;
96 struct regulator *vddio;
97 + u64 stats[ARRAY_SIZE(at803x_hw_stats)];
98 };
99
100 struct at803x_context {
101 @@ -165,6 +196,17 @@ struct at803x_context {
102 u16 led_control;
103 };
104
105 +static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
106 +{
107 + int ret;
108 +
109 + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
110 + if (ret < 0)
111 + return ret;
112 +
113 + return phy_write(phydev, AT803X_DEBUG_DATA, data);
114 +}
115 +
116 static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
117 {
118 int ret;
119 @@ -327,6 +369,53 @@ static void at803x_get_wol(struct phy_de
120 wol->wolopts |= WAKE_MAGIC;
121 }
122
123 +static int at803x_get_sset_count(struct phy_device *phydev)
124 +{
125 + return ARRAY_SIZE(at803x_hw_stats);
126 +}
127 +
128 +static void at803x_get_strings(struct phy_device *phydev, u8 *data)
129 +{
130 + int i;
131 +
132 + for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
133 + strscpy(data + i * ETH_GSTRING_LEN,
134 + at803x_hw_stats[i].string, ETH_GSTRING_LEN);
135 + }
136 +}
137 +
138 +static u64 at803x_get_stat(struct phy_device *phydev, int i)
139 +{
140 + struct at803x_hw_stat stat = at803x_hw_stats[i];
141 + struct at803x_priv *priv = phydev->priv;
142 + int val;
143 + u64 ret;
144 +
145 + if (stat.access_type == MMD)
146 + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
147 + else
148 + val = phy_read(phydev, stat.reg);
149 +
150 + if (val < 0) {
151 + ret = U64_MAX;
152 + } else {
153 + val = val & stat.mask;
154 + priv->stats[i] += val;
155 + ret = priv->stats[i];
156 + }
157 +
158 + return ret;
159 +}
160 +
161 +static void at803x_get_stats(struct phy_device *phydev,
162 + struct ethtool_stats *stats, u64 *data)
163 +{
164 + int i;
165 +
166 + for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
167 + data[i] = at803x_get_stat(phydev, i);
168 +}
169 +
170 static int at803x_suspend(struct phy_device *phydev)
171 {
172 int value;
173 @@ -1102,6 +1191,34 @@ static int at803x_cable_test_start(struc
174 return 0;
175 }
176
177 +static int qca83xx_config_init(struct phy_device *phydev)
178 +{
179 + u8 switch_revision;
180 +
181 + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
182 +
183 + switch (switch_revision) {
184 + case 1:
185 + /* For 100M waveform */
186 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea);
187 + /* Turn on Gigabit clock */
188 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0);
189 + break;
190 +
191 + case 2:
192 + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
193 + fallthrough;
194 + case 4:
195 + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
196 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860);
197 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46);
198 + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
199 + break;
200 + }
201 +
202 + return 0;
203 +}
204 +
205 static struct phy_driver at803x_driver[] = {
206 {
207 /* Qualcomm Atheros AR8035 */
208 @@ -1198,7 +1315,20 @@ static struct phy_driver at803x_driver[]
209 .read_status = at803x_read_status,
210 .soft_reset = genphy_soft_reset,
211 .config_aneg = at803x_config_aneg,
212 -} };
213 +}, {
214 + /* QCA8337 */
215 + .phy_id = QCA8337_PHY_ID,
216 + .phy_id_mask = QCA8K_PHY_ID_MASK,
217 + .name = "QCA PHY 8337",
218 + /* PHY_GBIT_FEATURES */
219 + .probe = at803x_probe,
220 + .flags = PHY_IS_INTERNAL,
221 + .config_init = qca83xx_config_init,
222 + .soft_reset = genphy_soft_reset,
223 + .get_sset_count = at803x_get_sset_count,
224 + .get_strings = at803x_get_strings,
225 + .get_stats = at803x_get_stats,
226 +}, };
227
228 module_phy_driver(at803x_driver);
229