blob: da710523b7c4192adcf19e8f995e4b82ae27ae73 [file] [log] [blame]
Andrew Lunna2443fd2019-01-21 19:05:50 +01001// SPDX-License-Identifier: GPL-2.0+
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00002/*
3 * drivers/net/phy/at803x.c
4 *
Michael Walle96c36712019-11-06 23:36:16 +01005 * Driver for Qualcomm Atheros AR803x PHY
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00006 *
7 * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00008 */
9
10#include <linux/phy.h>
11#include <linux/module.h>
12#include <linux/string.h>
13#include <linux/netdevice.h>
14#include <linux/etherdevice.h>
Michael Walle6cb75762020-05-13 22:38:07 +020015#include <linux/ethtool_netlink.h>
Daniel Mack13a56b42014-06-18 11:01:43 +020016#include <linux/of_gpio.h>
Michael Walle2f664822019-11-06 23:36:14 +010017#include <linux/bitfield.h>
Daniel Mack13a56b42014-06-18 11:01:43 +020018#include <linux/gpio/consumer.h>
Michael Walle2f664822019-11-06 23:36:14 +010019#include <linux/regulator/of_regulator.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/consumer.h>
22#include <dt-bindings/net/qca-ar803x.h>
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000023
Oleksij Rempel7dce80c2020-07-19 10:05:30 +020024#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
25#define AT803X_SFC_ASSERT_CRS BIT(11)
26#define AT803X_SFC_FORCE_LINK BIT(10)
27#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
28#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
29#define AT803X_SFC_MANUAL_MDIX 0x1
30#define AT803X_SFC_MANUAL_MDI 0x0
31#define AT803X_SFC_SQE_TEST BIT(2)
32#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
33#define AT803X_SFC_DISABLE_JABBER BIT(0)
34
Russell King06d5f342019-10-04 17:06:14 +010035#define AT803X_SPECIFIC_STATUS 0x11
Luo Jie9540cdd2021-10-24 16:27:28 +080036#define AT803X_SS_SPEED_MASK GENMASK(15, 14)
37#define AT803X_SS_SPEED_1000 2
38#define AT803X_SS_SPEED_100 1
39#define AT803X_SS_SPEED_10 0
Russell King06d5f342019-10-04 17:06:14 +010040#define AT803X_SS_DUPLEX BIT(13)
41#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
42#define AT803X_SS_MDIX BIT(6)
43
Luo Jie79c7bc02021-10-24 16:27:30 +080044#define QCA808X_SS_SPEED_MASK GENMASK(9, 7)
45#define QCA808X_SS_SPEED_2500 4
46
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000047#define AT803X_INTR_ENABLE 0x12
Martin Blumenstingle6e4a552016-01-15 01:55:24 +010048#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
49#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
50#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
51#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12)
52#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11)
53#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10)
54#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5)
55#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1)
56#define AT803X_INTR_ENABLE_WOL BIT(0)
57
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000058#define AT803X_INTR_STATUS 0x13
Martin Blumenstingla46bd632016-01-15 01:55:23 +010059
Daniel Mack13a56b42014-06-18 11:01:43 +020060#define AT803X_SMART_SPEED 0x14
Michael Wallecde0f4f2020-04-28 23:15:02 +020061#define AT803X_SMART_SPEED_ENABLE BIT(5)
62#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
63#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
Michael Walle6cb75762020-05-13 22:38:07 +020064#define AT803X_CDT 0x16
65#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8)
66#define AT803X_CDT_ENABLE_TEST BIT(0)
67#define AT803X_CDT_STATUS 0x1c
68#define AT803X_CDT_STATUS_STAT_NORMAL 0
69#define AT803X_CDT_STATUS_STAT_SHORT 1
70#define AT803X_CDT_STATUS_STAT_OPEN 2
71#define AT803X_CDT_STATUS_STAT_FAIL 3
72#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
73#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
Daniel Mack13a56b42014-06-18 11:01:43 +020074#define AT803X_LED_CONTROL 0x18
Martin Blumenstingla46bd632016-01-15 01:55:23 +010075
Luo Jie7beecaf2021-10-24 16:27:27 +080076#define AT803X_PHY_MMD3_WOL_CTRL 0x8012
77#define AT803X_WOL_EN BIT(5)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +000078#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
79#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
80#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
Zefir Kurtisif62265b2016-10-24 12:40:54 +020081#define AT803X_REG_CHIP_CONFIG 0x1f
82#define AT803X_BT_BX_REG_SEL 0x8000
Martin Blumenstingla46bd632016-01-15 01:55:23 +010083
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +000084#define AT803X_DEBUG_ADDR 0x1D
85#define AT803X_DEBUG_DATA 0x1E
Martin Blumenstingla46bd632016-01-15 01:55:23 +010086
Zefir Kurtisif62265b2016-10-24 12:40:54 +020087#define AT803X_MODE_CFG_MASK 0x0F
88#define AT803X_MODE_CFG_SGMII 0x01
89
Ansuel Smithd0e13fd2021-05-14 23:00:14 +020090#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
91#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
Zefir Kurtisif62265b2016-10-24 12:40:54 +020092
Ansuel Smith67999552021-10-10 00:46:18 +020093#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00
Ansuel Smith1ca83112021-10-10 00:46:16 +020094#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2)
95#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +010096#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
Martin Blumenstingla46bd632016-01-15 01:55:23 +010097
Ansuel Smith67999552021-10-10 00:46:18 +020098#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +010099#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000100
Ansuel Smithba3c01e2021-10-10 00:46:15 +0200101#define AT803X_DEBUG_REG_HIB_CTRL 0x0b
102#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10)
103#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13)
104
Ansuel Smith272833b2021-05-14 23:00:15 +0200105#define AT803X_DEBUG_REG_3C 0x3C
106
Ansuel Smith67999552021-10-10 00:46:18 +0200107#define AT803X_DEBUG_REG_GREEN 0x3D
Ansuel Smithba3c01e2021-10-10 00:46:15 +0200108#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
Ansuel Smith272833b2021-05-14 23:00:15 +0200109
Michael Walle2f664822019-11-06 23:36:14 +0100110#define AT803X_DEBUG_REG_1F 0x1F
111#define AT803X_DEBUG_PLL_ON BIT(2)
112#define AT803X_DEBUG_RGMII_1V8 BIT(3)
113
Ansuel Smith272833b2021-05-14 23:00:15 +0200114#define MDIO_AZ_DEBUG 0x800D
115
Michael Walle2f664822019-11-06 23:36:14 +0100116/* AT803x supports either the XTAL input pad, an internal PLL or the
117 * DSP as clock reference for the clock output pad. The XTAL reference
118 * is only used for 25 MHz output, all other frequencies need the PLL.
119 * The DSP as a clock reference is used in synchronous ethernet
120 * applications.
121 *
122 * By default the PLL is only enabled if there is a link. Otherwise
123 * the PHY will go into low power state and disabled the PLL. You can
124 * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always
125 * enabled.
126 */
127#define AT803X_MMD7_CLK25M 0x8016
128#define AT803X_CLK_OUT_MASK GENMASK(4, 2)
129#define AT803X_CLK_OUT_25MHZ_XTAL 0
130#define AT803X_CLK_OUT_25MHZ_DSP 1
131#define AT803X_CLK_OUT_50MHZ_PLL 2
132#define AT803X_CLK_OUT_50MHZ_DSP 3
133#define AT803X_CLK_OUT_62_5MHZ_PLL 4
134#define AT803X_CLK_OUT_62_5MHZ_DSP 5
135#define AT803X_CLK_OUT_125MHZ_PLL 6
136#define AT803X_CLK_OUT_125MHZ_DSP 7
137
Michael Walle428061f2019-11-06 23:36:15 +0100138/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask
139 * but doesn't support choosing between XTAL/PLL and DSP.
Michael Walle2f664822019-11-06 23:36:14 +0100140 */
141#define AT8035_CLK_OUT_MASK GENMASK(4, 3)
142
143#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7)
144#define AT803X_CLK_OUT_STRENGTH_FULL 0
145#define AT803X_CLK_OUT_STRENGTH_HALF 1
146#define AT803X_CLK_OUT_STRENGTH_QUARTER 2
147
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200148#define AT803X_DEFAULT_DOWNSHIFT 5
149#define AT803X_MIN_DOWNSHIFT 2
150#define AT803X_MAX_DOWNSHIFT 9
Michael Wallecde0f4f2020-04-28 23:15:02 +0200151
Russell King390b4ca2021-01-14 10:45:49 +0000152#define AT803X_MMD3_SMARTEEE_CTL1 0x805b
153#define AT803X_MMD3_SMARTEEE_CTL2 0x805c
154#define AT803X_MMD3_SMARTEEE_CTL3 0x805d
155#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8)
156
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200157#define ATH9331_PHY_ID 0x004dd041
158#define ATH8030_PHY_ID 0x004dd076
159#define ATH8031_PHY_ID 0x004dd074
160#define ATH8032_PHY_ID 0x004dd023
161#define ATH8035_PHY_ID 0x004dd072
Michael Walle0465d8f2020-05-22 11:53:31 +0200162#define AT8030_PHY_ID_MASK 0xffffffef
Daniel Mackbd8ca172014-06-18 11:01:42 +0200163
Luo Jiedaf61732021-10-24 16:27:29 +0800164#define QCA8081_PHY_ID 0x004dd101
165
Ansuel Smithb4df02b2021-09-19 18:28:15 +0200166#define QCA8327_A_PHY_ID 0x004dd033
167#define QCA8327_B_PHY_ID 0x004dd034
Ansuel Smith272833b2021-05-14 23:00:15 +0200168#define QCA8337_PHY_ID 0x004dd036
David Bauerfada2ce2021-10-06 00:54:01 +0200169#define QCA9561_PHY_ID 0x004dd042
Ansuel Smith272833b2021-05-14 23:00:15 +0200170#define QCA8K_PHY_ID_MASK 0xffffffff
171
172#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
173
Ansuel Smithd0e13fd2021-05-14 23:00:14 +0200174#define AT803X_PAGE_FIBER 0
175#define AT803X_PAGE_COPPER 1
176
177/* don't turn off internal PLL */
178#define AT803X_KEEP_PLL_ENABLED BIT(0)
179#define AT803X_DISABLE_SMARTEEE BIT(1)
David Bauerc329e5a2021-04-15 03:26:50 +0200180
Luo Jie2acdd43f2021-10-24 16:27:35 +0800181/* ADC threshold */
182#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80
183#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0)
184#define QCA808X_ADC_THRESHOLD_80MV 0
185#define QCA808X_ADC_THRESHOLD_100MV 0xf0
186#define QCA808X_ADC_THRESHOLD_200MV 0x0f
187#define QCA808X_ADC_THRESHOLD_300MV 0xff
188
189/* CLD control */
190#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007
191#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4)
192#define QCA808X_8023AZ_AFE_EN 0x90
193
194/* AZ control */
195#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008
196#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32
197
198#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014
199#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529
200
201#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E
202#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341
203
204#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E
205#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419
206
207#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020
208#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341
209
210#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c
211#define QCA808X_TOP_OPTION1_DATA 0x0
212
213#define QCA808X_PHY_MMD3_DEBUG_1 0xa100
214#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203
215#define QCA808X_PHY_MMD3_DEBUG_2 0xa101
216#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad
217#define QCA808X_PHY_MMD3_DEBUG_3 0xa103
218#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698
219#define QCA808X_PHY_MMD3_DEBUG_4 0xa105
220#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001
221#define QCA808X_PHY_MMD3_DEBUG_5 0xa106
222#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111
223#define QCA808X_PHY_MMD3_DEBUG_6 0xa011
224#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85
225
Luo Jiedaf61732021-10-24 16:27:29 +0800226MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000227MODULE_AUTHOR("Matus Ujhelyi");
228MODULE_LICENSE("GPL");
229
Ansuel Smith272833b2021-05-14 23:00:15 +0200230enum stat_access_type {
231 PHY,
232 MMD
233};
234
235struct at803x_hw_stat {
236 const char *string;
237 u8 reg;
238 u32 mask;
239 enum stat_access_type access_type;
240};
241
242static struct at803x_hw_stat at803x_hw_stats[] = {
243 { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
244 { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
245 { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
246};
247
Michael Walle2f664822019-11-06 23:36:14 +0100248struct at803x_priv {
249 int flags;
Michael Walle2f664822019-11-06 23:36:14 +0100250 u16 clk_25m_reg;
251 u16 clk_25m_mask;
Russell King390b4ca2021-01-14 10:45:49 +0000252 u8 smarteee_lpi_tw_1g;
253 u8 smarteee_lpi_tw_100m;
Michael Walle2f664822019-11-06 23:36:14 +0100254 struct regulator_dev *vddio_rdev;
255 struct regulator_dev *vddh_rdev;
256 struct regulator *vddio;
Ansuel Smith272833b2021-05-14 23:00:15 +0200257 u64 stats[ARRAY_SIZE(at803x_hw_stats)];
Michael Walle2f664822019-11-06 23:36:14 +0100258};
259
Daniel Mack13a56b42014-06-18 11:01:43 +0200260struct at803x_context {
261 u16 bmcr;
262 u16 advertise;
263 u16 control1000;
264 u16 int_enable;
265 u16 smart_speed;
266 u16 led_control;
267};
268
Ansuel Smith272833b2021-05-14 23:00:15 +0200269static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
270{
271 int ret;
272
273 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
274 if (ret < 0)
275 return ret;
276
277 return phy_write(phydev, AT803X_DEBUG_DATA, data);
278}
279
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100280static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
281{
282 int ret;
283
284 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
285 if (ret < 0)
286 return ret;
287
288 return phy_read(phydev, AT803X_DEBUG_DATA);
289}
290
291static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
292 u16 clear, u16 set)
293{
294 u16 val;
295 int ret;
296
297 ret = at803x_debug_reg_read(phydev, reg);
298 if (ret < 0)
299 return ret;
300
301 val = ret & 0xffff;
302 val &= ~clear;
303 val |= set;
304
305 return phy_write(phydev, AT803X_DEBUG_DATA, val);
306}
307
David Bauerc329e5a2021-04-15 03:26:50 +0200308static int at803x_write_page(struct phy_device *phydev, int page)
309{
310 int mask;
311 int set;
312
313 if (page == AT803X_PAGE_COPPER) {
314 set = AT803X_BT_BX_REG_SEL;
315 mask = 0;
316 } else {
317 set = 0;
318 mask = AT803X_BT_BX_REG_SEL;
319 }
320
321 return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
322}
323
324static int at803x_read_page(struct phy_device *phydev)
325{
326 int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
327
328 if (ccr < 0)
329 return ccr;
330
331 if (ccr & AT803X_BT_BX_REG_SEL)
332 return AT803X_PAGE_COPPER;
333
334 return AT803X_PAGE_FIBER;
335}
336
Vinod Koul6d4cd042019-02-21 15:53:15 +0530337static int at803x_enable_rx_delay(struct phy_device *phydev)
338{
Ansuel Smith67999552021-10-10 00:46:18 +0200339 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
Vinod Koul6d4cd042019-02-21 15:53:15 +0530340 AT803X_DEBUG_RX_CLK_DLY_EN);
341}
342
343static int at803x_enable_tx_delay(struct phy_device *phydev)
344{
Ansuel Smith67999552021-10-10 00:46:18 +0200345 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
Vinod Koul6d4cd042019-02-21 15:53:15 +0530346 AT803X_DEBUG_TX_CLK_DLY_EN);
347}
348
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530349static int at803x_disable_rx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100350{
Ansuel Smith67999552021-10-10 00:46:18 +0200351 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530352 AT803X_DEBUG_RX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100353}
354
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530355static int at803x_disable_tx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100356{
Ansuel Smith67999552021-10-10 00:46:18 +0200357 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530358 AT803X_DEBUG_TX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100359}
360
Daniel Mack13a56b42014-06-18 11:01:43 +0200361/* save relevant PHY registers to private copy */
362static void at803x_context_save(struct phy_device *phydev,
363 struct at803x_context *context)
364{
365 context->bmcr = phy_read(phydev, MII_BMCR);
366 context->advertise = phy_read(phydev, MII_ADVERTISE);
367 context->control1000 = phy_read(phydev, MII_CTRL1000);
368 context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
369 context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
370 context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
371}
372
373/* restore relevant PHY registers from private copy */
374static void at803x_context_restore(struct phy_device *phydev,
375 const struct at803x_context *context)
376{
377 phy_write(phydev, MII_BMCR, context->bmcr);
378 phy_write(phydev, MII_ADVERTISE, context->advertise);
379 phy_write(phydev, MII_CTRL1000, context->control1000);
380 phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
381 phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
382 phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
383}
384
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000385static int at803x_set_wol(struct phy_device *phydev,
386 struct ethtool_wolinfo *wol)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000387{
388 struct net_device *ndev = phydev->attached_dev;
389 const u8 *mac;
Luo Jie7beecaf2021-10-24 16:27:27 +0800390 int ret, irq_enabled;
Luo Jiec0f0b562021-10-24 16:27:25 +0800391 unsigned int i;
392 const unsigned int offsets[] = {
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000393 AT803X_LOC_MAC_ADDR_32_47_OFFSET,
394 AT803X_LOC_MAC_ADDR_16_31_OFFSET,
395 AT803X_LOC_MAC_ADDR_0_15_OFFSET,
396 };
397
398 if (!ndev)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000399 return -ENODEV;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000400
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000401 if (wol->wolopts & WAKE_MAGIC) {
402 mac = (const u8 *) ndev->dev_addr;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000403
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000404 if (!is_valid_ether_addr(mac))
Dan Murphyfc755682017-10-10 12:42:56 -0500405 return -EINVAL;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000406
Carlo Caione0e021392019-01-25 12:35:10 +0000407 for (i = 0; i < 3; i++)
Luo Jiec0f0b562021-10-24 16:27:25 +0800408 phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
Carlo Caione0e021392019-01-25 12:35:10 +0000409 mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000410
Luo Jie7beecaf2021-10-24 16:27:27 +0800411 /* Enable WOL function */
412 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL,
413 0, AT803X_WOL_EN);
414 if (ret)
415 return ret;
416 /* Enable WOL interrupt */
Luo Jie2d4284e2021-10-24 16:27:26 +0800417 ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000418 if (ret)
419 return ret;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000420 } else {
Luo Jie7beecaf2021-10-24 16:27:27 +0800421 /* Disable WoL function */
422 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL,
423 AT803X_WOL_EN, 0);
424 if (ret)
425 return ret;
426 /* Disable WOL interrupt */
Luo Jie2d4284e2021-10-24 16:27:26 +0800427 ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000428 if (ret)
429 return ret;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000430 }
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000431
Luo Jie7beecaf2021-10-24 16:27:27 +0800432 /* Clear WOL status */
433 ret = phy_read(phydev, AT803X_INTR_STATUS);
434 if (ret < 0)
435 return ret;
436
437 /* Check if there are other interrupts except for WOL triggered when PHY is
438 * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
439 * be passed up to the interrupt PIN.
440 */
441 irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
442 if (irq_enabled < 0)
443 return irq_enabled;
444
445 irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
446 if (ret & irq_enabled && !phy_polling_mode(phydev))
447 phy_trigger_machine(phydev);
448
449 return 0;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000450}
451
452static void at803x_get_wol(struct phy_device *phydev,
453 struct ethtool_wolinfo *wol)
454{
455 u32 value;
456
457 wol->supported = WAKE_MAGIC;
458 wol->wolopts = 0;
459
Luo Jie7beecaf2021-10-24 16:27:27 +0800460 value = phy_read_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL);
461 if (value < 0)
462 return;
463
464 if (value & AT803X_WOL_EN)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000465 wol->wolopts |= WAKE_MAGIC;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000466}
467
Ansuel Smith272833b2021-05-14 23:00:15 +0200468static int at803x_get_sset_count(struct phy_device *phydev)
469{
470 return ARRAY_SIZE(at803x_hw_stats);
471}
472
473static void at803x_get_strings(struct phy_device *phydev, u8 *data)
474{
475 int i;
476
477 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
478 strscpy(data + i * ETH_GSTRING_LEN,
479 at803x_hw_stats[i].string, ETH_GSTRING_LEN);
480 }
481}
482
483static u64 at803x_get_stat(struct phy_device *phydev, int i)
484{
485 struct at803x_hw_stat stat = at803x_hw_stats[i];
486 struct at803x_priv *priv = phydev->priv;
487 int val;
488 u64 ret;
489
490 if (stat.access_type == MMD)
491 val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
492 else
493 val = phy_read(phydev, stat.reg);
494
495 if (val < 0) {
496 ret = U64_MAX;
497 } else {
498 val = val & stat.mask;
499 priv->stats[i] += val;
500 ret = priv->stats[i];
501 }
502
503 return ret;
504}
505
506static void at803x_get_stats(struct phy_device *phydev,
507 struct ethtool_stats *stats, u64 *data)
508{
509 int i;
510
511 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
512 data[i] = at803x_get_stat(phydev, i);
513}
514
Daniel Mack6229ed12013-09-21 16:53:02 +0200515static int at803x_suspend(struct phy_device *phydev)
516{
517 int value;
518 int wol_enabled;
519
Daniel Mack6229ed12013-09-21 16:53:02 +0200520 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100521 wol_enabled = value & AT803X_INTR_ENABLE_WOL;
Daniel Mack6229ed12013-09-21 16:53:02 +0200522
Daniel Mack6229ed12013-09-21 16:53:02 +0200523 if (wol_enabled)
Russell Kingfea23fb2018-01-02 10:58:58 +0000524 value = BMCR_ISOLATE;
Daniel Mack6229ed12013-09-21 16:53:02 +0200525 else
Russell Kingfea23fb2018-01-02 10:58:58 +0000526 value = BMCR_PDOWN;
Daniel Mack6229ed12013-09-21 16:53:02 +0200527
Russell Kingfea23fb2018-01-02 10:58:58 +0000528 phy_modify(phydev, MII_BMCR, 0, value);
Daniel Mack6229ed12013-09-21 16:53:02 +0200529
530 return 0;
531}
532
533static int at803x_resume(struct phy_device *phydev)
534{
Russell Kingf1028522018-01-05 16:07:10 +0000535 return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
Daniel Mack6229ed12013-09-21 16:53:02 +0200536}
537
Michael Walle2f664822019-11-06 23:36:14 +0100538static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
539 unsigned int selector)
540{
541 struct phy_device *phydev = rdev_get_drvdata(rdev);
542
543 if (selector)
544 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
545 0, AT803X_DEBUG_RGMII_1V8);
546 else
547 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
548 AT803X_DEBUG_RGMII_1V8, 0);
549}
550
551static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
552{
553 struct phy_device *phydev = rdev_get_drvdata(rdev);
554 int val;
555
556 val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
557 if (val < 0)
558 return val;
559
560 return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
561}
562
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200563static const struct regulator_ops vddio_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100564 .list_voltage = regulator_list_voltage_table,
565 .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
566 .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
567};
568
569static const unsigned int vddio_voltage_table[] = {
570 1500000,
571 1800000,
572};
573
574static const struct regulator_desc vddio_desc = {
575 .name = "vddio",
576 .of_match = of_match_ptr("vddio-regulator"),
577 .n_voltages = ARRAY_SIZE(vddio_voltage_table),
578 .volt_table = vddio_voltage_table,
579 .ops = &vddio_regulator_ops,
580 .type = REGULATOR_VOLTAGE,
581 .owner = THIS_MODULE,
582};
583
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200584static const struct regulator_ops vddh_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100585};
586
587static const struct regulator_desc vddh_desc = {
588 .name = "vddh",
589 .of_match = of_match_ptr("vddh-regulator"),
590 .n_voltages = 1,
591 .fixed_uV = 2500000,
592 .ops = &vddh_regulator_ops,
593 .type = REGULATOR_VOLTAGE,
594 .owner = THIS_MODULE,
595};
596
597static int at8031_register_regulators(struct phy_device *phydev)
598{
599 struct at803x_priv *priv = phydev->priv;
600 struct device *dev = &phydev->mdio.dev;
601 struct regulator_config config = { };
602
603 config.dev = dev;
604 config.driver_data = phydev;
605
606 priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
607 if (IS_ERR(priv->vddio_rdev)) {
608 phydev_err(phydev, "failed to register VDDIO regulator\n");
609 return PTR_ERR(priv->vddio_rdev);
610 }
611
612 priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
613 if (IS_ERR(priv->vddh_rdev)) {
614 phydev_err(phydev, "failed to register VDDH regulator\n");
615 return PTR_ERR(priv->vddh_rdev);
616 }
617
618 return 0;
619}
620
Michael Walle2f664822019-11-06 23:36:14 +0100621static int at803x_parse_dt(struct phy_device *phydev)
622{
623 struct device_node *node = phydev->mdio.dev.of_node;
624 struct at803x_priv *priv = phydev->priv;
Russell King390b4ca2021-01-14 10:45:49 +0000625 u32 freq, strength, tw;
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200626 unsigned int sel;
Michael Walle2f664822019-11-06 23:36:14 +0100627 int ret;
628
629 if (!IS_ENABLED(CONFIG_OF_MDIO))
630 return 0;
631
Russell King390b4ca2021-01-14 10:45:49 +0000632 if (of_property_read_bool(node, "qca,disable-smarteee"))
633 priv->flags |= AT803X_DISABLE_SMARTEEE;
634
635 if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) {
636 if (!tw || tw > 255) {
637 phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n");
638 return -EINVAL;
639 }
640 priv->smarteee_lpi_tw_1g = tw;
641 }
642
643 if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) {
644 if (!tw || tw > 255) {
645 phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n");
646 return -EINVAL;
647 }
648 priv->smarteee_lpi_tw_100m = tw;
649 }
650
Michael Walle2f664822019-11-06 23:36:14 +0100651 ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
652 if (!ret) {
Michael Walle2f664822019-11-06 23:36:14 +0100653 switch (freq) {
654 case 25000000:
655 sel = AT803X_CLK_OUT_25MHZ_XTAL;
656 break;
657 case 50000000:
658 sel = AT803X_CLK_OUT_50MHZ_PLL;
659 break;
660 case 62500000:
661 sel = AT803X_CLK_OUT_62_5MHZ_PLL;
662 break;
663 case 125000000:
664 sel = AT803X_CLK_OUT_125MHZ_PLL;
665 break;
666 default:
667 phydev_err(phydev, "invalid qca,clk-out-frequency\n");
668 return -EINVAL;
669 }
670
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200671 priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
672 priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100673
674 /* Fixup for the AR8030/AR8035. This chip has another mask and
675 * doesn't support the DSP reference. Eg. the lowest bit of the
676 * mask. The upper two bits select the same frequencies. Mask
677 * the lowest bit here.
678 *
679 * Warning:
680 * There was no datasheet for the AR8030 available so this is
681 * just a guess. But the AR8035 is listed as pin compatible
682 * to the AR8030 so there might be a good chance it works on
683 * the AR8030 too.
684 */
Russell King8887ca52021-07-20 14:33:49 +0100685 if (phydev->drv->phy_id == ATH8030_PHY_ID ||
686 phydev->drv->phy_id == ATH8035_PHY_ID) {
Oleksij Rempelb1f4c202020-04-01 11:57:32 +0200687 priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
688 priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100689 }
690 }
691
692 ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
693 if (!ret) {
694 priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
695 switch (strength) {
696 case AR803X_STRENGTH_FULL:
697 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
698 break;
699 case AR803X_STRENGTH_HALF:
700 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
701 break;
702 case AR803X_STRENGTH_QUARTER:
703 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
704 break;
705 default:
706 phydev_err(phydev, "invalid qca,clk-out-strength\n");
707 return -EINVAL;
708 }
709 }
710
Michael Walle428061f2019-11-06 23:36:15 +0100711 /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
712 * options.
713 */
Russell King8887ca52021-07-20 14:33:49 +0100714 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100715 if (of_property_read_bool(node, "qca,keep-pll-enabled"))
716 priv->flags |= AT803X_KEEP_PLL_ENABLED;
717
718 ret = at8031_register_regulators(phydev);
719 if (ret < 0)
720 return ret;
721
722 priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev,
723 "vddio");
724 if (IS_ERR(priv->vddio)) {
725 phydev_err(phydev, "failed to get VDDIO regulator\n");
726 return PTR_ERR(priv->vddio);
727 }
Michael Walle2f664822019-11-06 23:36:14 +0100728 }
729
730 return 0;
731}
732
733static int at803x_probe(struct phy_device *phydev)
734{
735 struct device *dev = &phydev->mdio.dev;
736 struct at803x_priv *priv;
David Bauerc329e5a2021-04-15 03:26:50 +0200737 int ret;
Michael Walle2f664822019-11-06 23:36:14 +0100738
739 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
740 if (!priv)
741 return -ENOMEM;
742
743 phydev->priv = priv;
744
David Bauerc329e5a2021-04-15 03:26:50 +0200745 ret = at803x_parse_dt(phydev);
746 if (ret)
747 return ret;
748
Michael Walle8f7e8762021-04-20 12:29:29 +0200749 if (priv->vddio) {
750 ret = regulator_enable(priv->vddio);
751 if (ret < 0)
752 return ret;
753 }
754
David Bauerc329e5a2021-04-15 03:26:50 +0200755 /* Some bootloaders leave the fiber page selected.
756 * Switch to the copper page, as otherwise we read
757 * the PHY capabilities from the fiber side.
758 */
Russell King8887ca52021-07-20 14:33:49 +0100759 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle8f7e8762021-04-20 12:29:29 +0200760 phy_lock_mdio_bus(phydev);
761 ret = at803x_write_page(phydev, AT803X_PAGE_COPPER);
762 phy_unlock_mdio_bus(phydev);
763 if (ret)
764 goto err;
David Bauerc329e5a2021-04-15 03:26:50 +0200765 }
766
Michael Walle8f7e8762021-04-20 12:29:29 +0200767 return 0;
768
769err:
770 if (priv->vddio)
771 regulator_disable(priv->vddio);
772
David Bauerc329e5a2021-04-15 03:26:50 +0200773 return ret;
Michael Walle2f664822019-11-06 23:36:14 +0100774}
775
Michael Walle2318ca82020-01-30 18:54:02 +0100776static void at803x_remove(struct phy_device *phydev)
777{
778 struct at803x_priv *priv = phydev->priv;
779
780 if (priv->vddio)
781 regulator_disable(priv->vddio);
782}
783
David Bauerb8561502021-06-27 12:16:07 +0200784static int at803x_get_features(struct phy_device *phydev)
785{
786 int err;
787
788 err = genphy_read_abilities(phydev);
789 if (err)
790 return err;
791
Luo Jie765c22a2021-10-24 16:27:31 +0800792 if (phydev->drv->phy_id == QCA8081_PHY_ID) {
793 err = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_NG_EXTABLE);
794 if (err < 0)
795 return err;
796
797 linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported,
798 err & MDIO_PMA_NG_EXTABLE_2_5GBT);
799 }
800
Vladimir Olteanf5621a02021-07-20 20:24:33 +0300801 if (phydev->drv->phy_id != ATH8031_PHY_ID)
David Bauerb8561502021-06-27 12:16:07 +0200802 return 0;
803
804 /* AR8031/AR8033 have different status registers
805 * for copper and fiber operation. However, the
806 * extended status register is the same for both
807 * operation modes.
808 *
809 * As a result of that, ESTATUS_1000_XFULL is set
810 * to 1 even when operating in copper TP mode.
811 *
812 * Remove this mode from the supported link modes,
813 * as this driver currently only supports copper
814 * operation.
815 */
816 linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
817 phydev->supported);
818 return 0;
819}
820
Russell King390b4ca2021-01-14 10:45:49 +0000821static int at803x_smarteee_config(struct phy_device *phydev)
822{
823 struct at803x_priv *priv = phydev->priv;
824 u16 mask = 0, val = 0;
825 int ret;
826
827 if (priv->flags & AT803X_DISABLE_SMARTEEE)
828 return phy_modify_mmd(phydev, MDIO_MMD_PCS,
829 AT803X_MMD3_SMARTEEE_CTL3,
830 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);
831
832 if (priv->smarteee_lpi_tw_1g) {
833 mask |= 0xff00;
834 val |= priv->smarteee_lpi_tw_1g << 8;
835 }
836 if (priv->smarteee_lpi_tw_100m) {
837 mask |= 0x00ff;
838 val |= priv->smarteee_lpi_tw_100m;
839 }
840 if (!mask)
841 return 0;
842
843 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1,
844 mask, val);
845 if (ret)
846 return ret;
847
848 return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
849 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
850 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
851}
852
Michael Walle2f664822019-11-06 23:36:14 +0100853static int at803x_clk_out_config(struct phy_device *phydev)
854{
855 struct at803x_priv *priv = phydev->priv;
Michael Walle2f664822019-11-06 23:36:14 +0100856
857 if (!priv->clk_25m_mask)
858 return 0;
859
Russell Kinga45c1c12021-01-10 14:54:36 +0000860 return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M,
861 priv->clk_25m_mask, priv->clk_25m_reg);
Michael Walle2f664822019-11-06 23:36:14 +0100862}
863
864static int at8031_pll_config(struct phy_device *phydev)
865{
866 struct at803x_priv *priv = phydev->priv;
867
868 /* The default after hardware reset is PLL OFF. After a soft reset, the
869 * values are retained.
870 */
871 if (priv->flags & AT803X_KEEP_PLL_ENABLED)
872 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
873 0, AT803X_DEBUG_PLL_ON);
874 else
875 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
876 AT803X_DEBUG_PLL_ON, 0);
877}
878
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000879static int at803x_config_init(struct phy_device *phydev)
880{
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000881 int ret;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000882
Vinod Koul6d4cd042019-02-21 15:53:15 +0530883 /* The RX and TX delay default is:
884 * after HW reset: RX delay enabled and TX delay disabled
885 * after SW reset: RX delay enabled, while TX delay retains the
886 * value before reset.
Vinod Koul6d4cd042019-02-21 15:53:15 +0530887 */
Vinod Koul6d4cd042019-02-21 15:53:15 +0530888 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100889 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530890 ret = at803x_enable_rx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100891 else
892 ret = at803x_disable_rx_delay(phydev);
893 if (ret < 0)
894 return ret;
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100895
Vinod Koul6d4cd042019-02-21 15:53:15 +0530896 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100897 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530898 ret = at803x_enable_tx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100899 else
900 ret = at803x_disable_tx_delay(phydev);
Michael Walle2f664822019-11-06 23:36:14 +0100901 if (ret < 0)
902 return ret;
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000903
Russell King390b4ca2021-01-14 10:45:49 +0000904 ret = at803x_smarteee_config(phydev);
905 if (ret < 0)
906 return ret;
907
Michael Walle2f664822019-11-06 23:36:14 +0100908 ret = at803x_clk_out_config(phydev);
909 if (ret < 0)
910 return ret;
911
Russell King8887ca52021-07-20 14:33:49 +0100912 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100913 ret = at8031_pll_config(phydev);
914 if (ret < 0)
915 return ret;
916 }
917
Russell King3c51fa52021-01-12 22:59:43 +0000918 /* Ar803x extended next page bit is enabled by default. Cisco
919 * multigig switches read this bit and attempt to negotiate 10Gbps
920 * rates even if the next page bit is disabled. This is incorrect
921 * behaviour but we still need to accommodate it. XNP is only needed
922 * for 10Gbps support, so disable XNP.
923 */
924 return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000925}
926
Zhao Qiang77a99392014-03-28 15:39:41 +0800927static int at803x_ack_interrupt(struct phy_device *phydev)
928{
929 int err;
930
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100931 err = phy_read(phydev, AT803X_INTR_STATUS);
Zhao Qiang77a99392014-03-28 15:39:41 +0800932
933 return (err < 0) ? err : 0;
934}
935
936static int at803x_config_intr(struct phy_device *phydev)
937{
938 int err;
939 int value;
940
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100941 value = phy_read(phydev, AT803X_INTR_ENABLE);
Zhao Qiang77a99392014-03-28 15:39:41 +0800942
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100943 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
Ioana Ciorneia3417882020-11-01 14:51:00 +0200944 /* Clear any pending interrupts */
945 err = at803x_ack_interrupt(phydev);
946 if (err)
947 return err;
948
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100949 value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
950 value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
951 value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
952 value |= AT803X_INTR_ENABLE_LINK_FAIL;
953 value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
954
955 err = phy_write(phydev, AT803X_INTR_ENABLE, value);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200956 } else {
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100957 err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200958 if (err)
959 return err;
960
961 /* Clear any pending interrupts */
962 err = at803x_ack_interrupt(phydev);
963 }
Zhao Qiang77a99392014-03-28 15:39:41 +0800964
965 return err;
966}
967
Ioana Ciornei29773092020-11-01 14:50:59 +0200968static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
969{
970 int irq_status, int_enabled;
971
972 irq_status = phy_read(phydev, AT803X_INTR_STATUS);
973 if (irq_status < 0) {
974 phy_error(phydev);
975 return IRQ_NONE;
976 }
977
978 /* Read the current enabled interrupts */
979 int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
980 if (int_enabled < 0) {
981 phy_error(phydev);
982 return IRQ_NONE;
983 }
984
985 /* See if this was one of our enabled interrupts */
986 if (!(irq_status & int_enabled))
987 return IRQ_NONE;
988
989 phy_trigger_machine(phydev);
990
991 return IRQ_HANDLED;
992}
993
Daniel Mack13a56b42014-06-18 11:01:43 +0200994static void at803x_link_change_notify(struct phy_device *phydev)
995{
Daniel Mack13a56b42014-06-18 11:01:43 +0200996 /*
997 * Conduct a hardware reset for AT8030 every time a link loss is
998 * signalled. This is necessary to circumvent a hardware bug that
999 * occurs when the cable is unplugged while TX packets are pending
1000 * in the FIFO. In such cases, the FIFO enters an error mode it
1001 * cannot recover from by software.
1002 */
David Bauer6110ed22019-04-17 23:59:22 +02001003 if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) {
Heiner Kallweit5c5f6262019-03-19 19:56:51 +01001004 struct at803x_context context;
Daniel Mack13a56b42014-06-18 11:01:43 +02001005
Heiner Kallweit5c5f6262019-03-19 19:56:51 +01001006 at803x_context_save(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +02001007
Heiner Kallweit5c5f6262019-03-19 19:56:51 +01001008 phy_device_reset(phydev, 1);
1009 msleep(1);
1010 phy_device_reset(phydev, 0);
1011 msleep(1);
Daniel Mack13a56b42014-06-18 11:01:43 +02001012
Heiner Kallweit5c5f6262019-03-19 19:56:51 +01001013 at803x_context_restore(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +02001014
Heiner Kallweit5c5f6262019-03-19 19:56:51 +01001015 phydev_dbg(phydev, "%s(): phy was reset\n", __func__);
Daniel Mack13a56b42014-06-18 11:01:43 +02001016 }
1017}
1018
Luo Jie79c7bc02021-10-24 16:27:30 +08001019static int at803x_read_specific_status(struct phy_device *phydev)
Russell King06d5f342019-10-04 17:06:14 +01001020{
Luo Jie79c7bc02021-10-24 16:27:30 +08001021 int ss;
Russell King06d5f342019-10-04 17:06:14 +01001022
1023 /* Read the AT8035 PHY-Specific Status register, which indicates the
1024 * speed and duplex that the PHY is actually using, irrespective of
1025 * whether we are in autoneg mode or not.
1026 */
1027 ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
1028 if (ss < 0)
1029 return ss;
1030
1031 if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
Luo Jie79c7bc02021-10-24 16:27:30 +08001032 int sfc, speed;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001033
1034 sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
1035 if (sfc < 0)
1036 return sfc;
1037
Luo Jie79c7bc02021-10-24 16:27:30 +08001038 /* qca8081 takes the different bits for speed value from at803x */
1039 if (phydev->drv->phy_id == QCA8081_PHY_ID)
1040 speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
1041 else
1042 speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
1043
1044 switch (speed) {
Russell King06d5f342019-10-04 17:06:14 +01001045 case AT803X_SS_SPEED_10:
1046 phydev->speed = SPEED_10;
1047 break;
1048 case AT803X_SS_SPEED_100:
1049 phydev->speed = SPEED_100;
1050 break;
1051 case AT803X_SS_SPEED_1000:
1052 phydev->speed = SPEED_1000;
1053 break;
Luo Jie79c7bc02021-10-24 16:27:30 +08001054 case QCA808X_SS_SPEED_2500:
1055 phydev->speed = SPEED_2500;
1056 break;
Russell King06d5f342019-10-04 17:06:14 +01001057 }
1058 if (ss & AT803X_SS_DUPLEX)
1059 phydev->duplex = DUPLEX_FULL;
1060 else
1061 phydev->duplex = DUPLEX_HALF;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001062
Russell King06d5f342019-10-04 17:06:14 +01001063 if (ss & AT803X_SS_MDIX)
1064 phydev->mdix = ETH_TP_MDI_X;
1065 else
1066 phydev->mdix = ETH_TP_MDI;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001067
1068 switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
1069 case AT803X_SFC_MANUAL_MDI:
1070 phydev->mdix_ctrl = ETH_TP_MDI;
1071 break;
1072 case AT803X_SFC_MANUAL_MDIX:
1073 phydev->mdix_ctrl = ETH_TP_MDI_X;
1074 break;
1075 case AT803X_SFC_AUTOMATIC_CROSSOVER:
1076 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1077 break;
1078 }
Russell King06d5f342019-10-04 17:06:14 +01001079 }
1080
Luo Jie79c7bc02021-10-24 16:27:30 +08001081 return 0;
1082}
1083
1084static int at803x_read_status(struct phy_device *phydev)
1085{
1086 int err, old_link = phydev->link;
1087
1088 /* Update the link, but return if there was an error */
1089 err = genphy_update_link(phydev);
1090 if (err)
1091 return err;
1092
1093 /* why bother the PHY if nothing can have changed */
1094 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
1095 return 0;
1096
1097 phydev->speed = SPEED_UNKNOWN;
1098 phydev->duplex = DUPLEX_UNKNOWN;
1099 phydev->pause = 0;
1100 phydev->asym_pause = 0;
1101
1102 err = genphy_read_lpa(phydev);
1103 if (err < 0)
1104 return err;
1105
1106 err = at803x_read_specific_status(phydev);
1107 if (err < 0)
1108 return err;
1109
Russell King06d5f342019-10-04 17:06:14 +01001110 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
1111 phy_resolve_aneg_pause(phydev);
1112
1113 return 0;
1114}
1115
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001116static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
1117{
1118 u16 val;
1119
1120 switch (ctrl) {
1121 case ETH_TP_MDI:
1122 val = AT803X_SFC_MANUAL_MDI;
1123 break;
1124 case ETH_TP_MDI_X:
1125 val = AT803X_SFC_MANUAL_MDIX;
1126 break;
1127 case ETH_TP_MDI_AUTO:
1128 val = AT803X_SFC_AUTOMATIC_CROSSOVER;
1129 break;
1130 default:
1131 return 0;
1132 }
1133
1134 return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
1135 AT803X_SFC_MDI_CROSSOVER_MODE_M,
1136 FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
1137}
1138
1139static int at803x_config_aneg(struct phy_device *phydev)
1140{
1141 int ret;
1142
1143 ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
1144 if (ret < 0)
1145 return ret;
1146
1147 /* Changes of the midx bits are disruptive to the normal operation;
1148 * therefore any changes to these registers must be followed by a
1149 * software reset to take effect.
1150 */
1151 if (ret == 1) {
1152 ret = genphy_soft_reset(phydev);
1153 if (ret < 0)
1154 return ret;
1155 }
1156
Luo Jief884d442021-10-24 16:27:32 +08001157 /* Do not restart auto-negotiation by setting ret to 0 defautly,
1158 * when calling __genphy_config_aneg later.
1159 */
1160 ret = 0;
1161
1162 if (phydev->drv->phy_id == QCA8081_PHY_ID) {
1163 int phy_ctrl = 0;
1164
1165 /* The reg MII_BMCR also needs to be configured for force mode, the
1166 * genphy_config_aneg is also needed.
1167 */
1168 if (phydev->autoneg == AUTONEG_DISABLE)
1169 genphy_c45_pma_setup_forced(phydev);
1170
1171 if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
1172 phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
1173
1174 ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
1175 MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
1176 if (ret < 0)
1177 return ret;
1178 }
1179
1180 return __genphy_config_aneg(phydev, ret);
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001181}
1182
Michael Wallecde0f4f2020-04-28 23:15:02 +02001183static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
1184{
1185 int val;
1186
1187 val = phy_read(phydev, AT803X_SMART_SPEED);
1188 if (val < 0)
1189 return val;
1190
1191 if (val & AT803X_SMART_SPEED_ENABLE)
1192 *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
1193 else
1194 *d = DOWNSHIFT_DEV_DISABLE;
1195
1196 return 0;
1197}
1198
1199static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
1200{
1201 u16 mask, set;
1202 int ret;
1203
1204 switch (cnt) {
1205 case DOWNSHIFT_DEV_DEFAULT_COUNT:
1206 cnt = AT803X_DEFAULT_DOWNSHIFT;
1207 fallthrough;
1208 case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
1209 set = AT803X_SMART_SPEED_ENABLE |
1210 AT803X_SMART_SPEED_BYPASS_TIMER |
1211 FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
1212 mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
1213 break;
1214 case DOWNSHIFT_DEV_DISABLE:
1215 set = 0;
1216 mask = AT803X_SMART_SPEED_ENABLE |
1217 AT803X_SMART_SPEED_BYPASS_TIMER;
1218 break;
1219 default:
1220 return -EINVAL;
1221 }
1222
1223 ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
1224
1225 /* After changing the smart speed settings, we need to perform a
1226 * software reset, use phy_init_hw() to make sure we set the
1227 * reapply any values which might got lost during software reset.
1228 */
1229 if (ret == 1)
1230 ret = phy_init_hw(phydev);
1231
1232 return ret;
1233}
1234
1235static int at803x_get_tunable(struct phy_device *phydev,
1236 struct ethtool_tunable *tuna, void *data)
1237{
1238 switch (tuna->id) {
1239 case ETHTOOL_PHY_DOWNSHIFT:
1240 return at803x_get_downshift(phydev, data);
1241 default:
1242 return -EOPNOTSUPP;
1243 }
1244}
1245
1246static int at803x_set_tunable(struct phy_device *phydev,
1247 struct ethtool_tunable *tuna, const void *data)
1248{
1249 switch (tuna->id) {
1250 case ETHTOOL_PHY_DOWNSHIFT:
1251 return at803x_set_downshift(phydev, *(const u8 *)data);
1252 default:
1253 return -EOPNOTSUPP;
1254 }
1255}
1256
Michael Walle6cb75762020-05-13 22:38:07 +02001257static int at803x_cable_test_result_trans(u16 status)
1258{
1259 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1260 case AT803X_CDT_STATUS_STAT_NORMAL:
1261 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
1262 case AT803X_CDT_STATUS_STAT_SHORT:
1263 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
1264 case AT803X_CDT_STATUS_STAT_OPEN:
1265 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
1266 case AT803X_CDT_STATUS_STAT_FAIL:
1267 default:
1268 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
1269 }
1270}
1271
1272static bool at803x_cdt_test_failed(u16 status)
1273{
1274 return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) ==
1275 AT803X_CDT_STATUS_STAT_FAIL;
1276}
1277
1278static bool at803x_cdt_fault_length_valid(u16 status)
1279{
1280 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1281 case AT803X_CDT_STATUS_STAT_OPEN:
1282 case AT803X_CDT_STATUS_STAT_SHORT:
1283 return true;
1284 }
1285 return false;
1286}
1287
1288static int at803x_cdt_fault_length(u16 status)
1289{
1290 int dt;
1291
1292 /* According to the datasheet the distance to the fault is
1293 * DELTA_TIME * 0.824 meters.
1294 *
1295 * The author suspect the correct formula is:
1296 *
1297 * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
1298 *
1299 * where c is the speed of light, VF is the velocity factor of
1300 * the twisted pair cable, 125MHz the counter frequency and
1301 * we need to divide by 2 because the hardware will measure the
1302 * round trip time to the fault and back to the PHY.
1303 *
1304 * With a VF of 0.69 we get the factor 0.824 mentioned in the
1305 * datasheet.
1306 */
1307 dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
1308
1309 return (dt * 824) / 10;
1310}
1311
1312static int at803x_cdt_start(struct phy_device *phydev, int pair)
1313{
1314 u16 cdt;
1315
1316 cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
1317 AT803X_CDT_ENABLE_TEST;
1318
1319 return phy_write(phydev, AT803X_CDT, cdt);
1320}
1321
1322static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
1323{
1324 int val, ret;
1325
1326 /* One test run takes about 25ms */
1327 ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
1328 !(val & AT803X_CDT_ENABLE_TEST),
1329 30000, 100000, true);
1330
1331 return ret < 0 ? ret : 0;
1332}
1333
1334static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
1335{
1336 static const int ethtool_pair[] = {
1337 ETHTOOL_A_CABLE_PAIR_A,
1338 ETHTOOL_A_CABLE_PAIR_B,
1339 ETHTOOL_A_CABLE_PAIR_C,
1340 ETHTOOL_A_CABLE_PAIR_D,
1341 };
1342 int ret, val;
1343
1344 ret = at803x_cdt_start(phydev, pair);
1345 if (ret)
1346 return ret;
1347
1348 ret = at803x_cdt_wait_for_completion(phydev);
1349 if (ret)
1350 return ret;
1351
1352 val = phy_read(phydev, AT803X_CDT_STATUS);
1353 if (val < 0)
1354 return val;
1355
1356 if (at803x_cdt_test_failed(val))
1357 return 0;
1358
1359 ethnl_cable_test_result(phydev, ethtool_pair[pair],
1360 at803x_cable_test_result_trans(val));
1361
1362 if (at803x_cdt_fault_length_valid(val))
1363 ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
1364 at803x_cdt_fault_length(val));
1365
1366 return 1;
1367}
1368
1369static int at803x_cable_test_get_status(struct phy_device *phydev,
1370 bool *finished)
1371{
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001372 unsigned long pair_mask;
Michael Walle6cb75762020-05-13 22:38:07 +02001373 int retries = 20;
1374 int pair, ret;
1375
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001376 if (phydev->phy_id == ATH9331_PHY_ID ||
David Bauerfada2ce2021-10-06 00:54:01 +02001377 phydev->phy_id == ATH8032_PHY_ID ||
1378 phydev->phy_id == QCA9561_PHY_ID)
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001379 pair_mask = 0x3;
1380 else
1381 pair_mask = 0xf;
1382
Michael Walle6cb75762020-05-13 22:38:07 +02001383 *finished = false;
1384
1385 /* According to the datasheet the CDT can be performed when
1386 * there is no link partner or when the link partner is
1387 * auto-negotiating. Starting the test will restart the AN
1388 * automatically. It seems that doing this repeatedly we will
1389 * get a slot where our link partner won't disturb our
1390 * measurement.
1391 */
1392 while (pair_mask && retries--) {
1393 for_each_set_bit(pair, &pair_mask, 4) {
1394 ret = at803x_cable_test_one_pair(phydev, pair);
1395 if (ret < 0)
1396 return ret;
1397 if (ret)
1398 clear_bit(pair, &pair_mask);
1399 }
1400 if (pair_mask)
1401 msleep(250);
1402 }
1403
1404 *finished = true;
1405
1406 return 0;
1407}
1408
1409static int at803x_cable_test_start(struct phy_device *phydev)
1410{
1411 /* Enable auto-negotiation, but advertise no capabilities, no link
1412 * will be established. A restart of the auto-negotiation is not
1413 * required, because the cable test will automatically break the link.
1414 */
1415 phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
1416 phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001417 if (phydev->phy_id != ATH9331_PHY_ID &&
David Bauerfada2ce2021-10-06 00:54:01 +02001418 phydev->phy_id != ATH8032_PHY_ID &&
1419 phydev->phy_id != QCA9561_PHY_ID)
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001420 phy_write(phydev, MII_CTRL1000, 0);
Michael Walle6cb75762020-05-13 22:38:07 +02001421
1422 /* we do all the (time consuming) work later */
1423 return 0;
1424}
1425
Ansuel Smith272833b2021-05-14 23:00:15 +02001426static int qca83xx_config_init(struct phy_device *phydev)
1427{
1428 u8 switch_revision;
1429
1430 switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
1431
1432 switch (switch_revision) {
1433 case 1:
1434 /* For 100M waveform */
Ansuel Smith67999552021-10-10 00:46:18 +02001435 at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
Ansuel Smith272833b2021-05-14 23:00:15 +02001436 /* Turn on Gigabit clock */
Ansuel Smith67999552021-10-10 00:46:18 +02001437 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
Ansuel Smith272833b2021-05-14 23:00:15 +02001438 break;
1439
1440 case 2:
1441 phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
1442 fallthrough;
1443 case 4:
1444 phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
Ansuel Smith67999552021-10-10 00:46:18 +02001445 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
1446 at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
Ansuel Smith272833b2021-05-14 23:00:15 +02001447 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
1448 break;
1449 }
1450
Ansuel Smith1ca83112021-10-10 00:46:16 +02001451 /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
1452 * Disable on init and enable only with 100m speed following
1453 * qca original source code.
1454 */
1455 if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
1456 phydev->drv->phy_id == QCA8327_B_PHY_ID)
Ansuel Smith67999552021-10-10 00:46:18 +02001457 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001458 QCA8327_DEBUG_MANU_CTRL_EN, 0);
1459
Ansuel Smith9d1c29b2021-10-10 00:46:17 +02001460 /* Following original QCA sourcecode set port to prefer master */
1461 phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
1462
Ansuel Smith272833b2021-05-14 23:00:15 +02001463 return 0;
1464}
1465
Ansuel Smith1ca83112021-10-10 00:46:16 +02001466static void qca83xx_link_change_notify(struct phy_device *phydev)
1467{
1468 /* QCA8337 doesn't require DAC Amplitude adjustement */
1469 if (phydev->drv->phy_id == QCA8337_PHY_ID)
1470 return;
1471
1472 /* Set DAC Amplitude adjustment to +6% for 100m on link running */
1473 if (phydev->state == PHY_RUNNING) {
1474 if (phydev->speed == SPEED_100)
Ansuel Smith67999552021-10-10 00:46:18 +02001475 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001476 QCA8327_DEBUG_MANU_CTRL_EN,
1477 QCA8327_DEBUG_MANU_CTRL_EN);
1478 } else {
1479 /* Reset DAC Amplitude adjustment */
Ansuel Smith67999552021-10-10 00:46:18 +02001480 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001481 QCA8327_DEBUG_MANU_CTRL_EN, 0);
1482 }
1483}
1484
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001485static int qca83xx_resume(struct phy_device *phydev)
1486{
1487 int ret, val;
1488
1489 /* Skip reset if not suspended */
1490 if (!phydev->suspended)
1491 return 0;
1492
1493 /* Reinit the port, reset values set by suspend */
1494 qca83xx_config_init(phydev);
1495
1496 /* Reset the port on port resume */
1497 phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
1498
1499 /* On resume from suspend the switch execute a reset and
1500 * restart auto-negotiation. Wait for reset to complete.
1501 */
1502 ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
1503 50000, 600000, true);
1504 if (ret)
1505 return ret;
1506
1507 msleep(1);
1508
1509 return 0;
1510}
1511
1512static int qca83xx_suspend(struct phy_device *phydev)
1513{
1514 u16 mask = 0;
1515
1516 /* Only QCA8337 support actual suspend.
1517 * QCA8327 cause port unreliability when phy suspend
1518 * is set.
1519 */
1520 if (phydev->drv->phy_id == QCA8337_PHY_ID) {
1521 genphy_suspend(phydev);
1522 } else {
1523 mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
1524 phy_modify(phydev, MII_BMCR, mask, 0);
1525 }
1526
Ansuel Smith67999552021-10-10 00:46:18 +02001527 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001528 AT803X_DEBUG_GATE_CLK_IN1000, 0);
1529
1530 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
1531 AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
1532 AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
1533
1534 return 0;
1535}
1536
Luo Jie2acdd43f2021-10-24 16:27:35 +08001537static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
1538{
1539 int ret;
1540
1541 /* Enable fast retrain */
1542 ret = genphy_c45_fast_retrain(phydev, true);
1543 if (ret)
1544 return ret;
1545
1546 phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
1547 QCA808X_TOP_OPTION1_DATA);
1548 phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
1549 QCA808X_MSE_THRESHOLD_20DB_VALUE);
1550 phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
1551 QCA808X_MSE_THRESHOLD_17DB_VALUE);
1552 phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
1553 QCA808X_MSE_THRESHOLD_27DB_VALUE);
1554 phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
1555 QCA808X_MSE_THRESHOLD_28DB_VALUE);
1556 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
1557 QCA808X_MMD3_DEBUG_1_VALUE);
1558 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
1559 QCA808X_MMD3_DEBUG_4_VALUE);
1560 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
1561 QCA808X_MMD3_DEBUG_5_VALUE);
1562 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
1563 QCA808X_MMD3_DEBUG_3_VALUE);
1564 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
1565 QCA808X_MMD3_DEBUG_6_VALUE);
1566 phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
1567 QCA808X_MMD3_DEBUG_2_VALUE);
1568
1569 return 0;
1570}
1571
1572static int qca808x_config_init(struct phy_device *phydev)
1573{
1574 int ret;
1575
1576 /* Active adc&vga on 802.3az for the link 1000M and 100M */
1577 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
1578 QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
1579 if (ret)
1580 return ret;
1581
1582 /* Adjust the threshold on 802.3az for the link 1000M */
1583 ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
1584 QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL);
1585 if (ret)
1586 return ret;
1587
1588 /* Config the fast retrain for the link 2500M */
1589 ret = qca808x_phy_fast_retrain_config(phydev);
1590 if (ret)
1591 return ret;
1592
1593 /* Configure adc threshold as 100mv for the link 10M */
1594 return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
1595 QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV);
1596}
1597
Luo Jie79c7bc02021-10-24 16:27:30 +08001598static int qca808x_read_status(struct phy_device *phydev)
1599{
1600 int ret;
1601
1602 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
1603 if (ret < 0)
1604 return ret;
1605
1606 linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
1607 ret & MDIO_AN_10GBT_STAT_LP2_5G);
1608
1609 ret = genphy_read_status(phydev);
1610 if (ret)
1611 return ret;
1612
1613 ret = at803x_read_specific_status(phydev);
1614 if (ret < 0)
1615 return ret;
1616
1617 if (phydev->link && phydev->speed == SPEED_2500)
1618 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
1619 else
1620 phydev->interface = PHY_INTERFACE_MODE_SMII;
1621
1622 return 0;
1623}
1624
Mugunthan V N317420a2013-06-03 20:10:04 +00001625static struct phy_driver at803x_driver[] = {
1626{
Michael Walle96c36712019-11-06 23:36:16 +01001627 /* Qualcomm Atheros AR8035 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001628 PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001629 .name = "Qualcomm Atheros AR8035",
Michael Walle6cb75762020-05-13 22:38:07 +02001630 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001631 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001632 .remove = at803x_remove,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001633 .config_aneg = at803x_config_aneg,
Daniel Mack13a56b42014-06-18 11:01:43 +02001634 .config_init = at803x_config_init,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001635 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001636 .set_wol = at803x_set_wol,
1637 .get_wol = at803x_get_wol,
1638 .suspend = at803x_suspend,
1639 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001640 /* PHY_GBIT_FEATURES */
Russell King06d5f342019-10-04 17:06:14 +01001641 .read_status = at803x_read_status,
Måns Rullgård0eae5982015-11-12 17:40:20 +00001642 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001643 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001644 .get_tunable = at803x_get_tunable,
1645 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001646 .cable_test_start = at803x_cable_test_start,
1647 .cable_test_get_status = at803x_cable_test_get_status,
Mugunthan V N317420a2013-06-03 20:10:04 +00001648}, {
Michael Walle96c36712019-11-06 23:36:16 +01001649 /* Qualcomm Atheros AR8030 */
Daniel Mack13a56b42014-06-18 11:01:43 +02001650 .phy_id = ATH8030_PHY_ID,
Michael Walle96c36712019-11-06 23:36:16 +01001651 .name = "Qualcomm Atheros AR8030",
Michael Walle0465d8f2020-05-22 11:53:31 +02001652 .phy_id_mask = AT8030_PHY_ID_MASK,
Michael Walle2f664822019-11-06 23:36:14 +01001653 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001654 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001655 .config_init = at803x_config_init,
1656 .link_change_notify = at803x_link_change_notify,
1657 .set_wol = at803x_set_wol,
1658 .get_wol = at803x_get_wol,
1659 .suspend = at803x_suspend,
1660 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001661 /* PHY_BASIC_FEATURES */
Måns Rullgård0eae5982015-11-12 17:40:20 +00001662 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001663 .handle_interrupt = at803x_handle_interrupt,
Mugunthan V N05d7cce2013-06-03 20:10:07 +00001664}, {
Michael Walle96c36712019-11-06 23:36:16 +01001665 /* Qualcomm Atheros AR8031/AR8033 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001666 PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001667 .name = "Qualcomm Atheros AR8031/AR8033",
Michael Walle6cb75762020-05-13 22:38:07 +02001668 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001669 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001670 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001671 .config_init = at803x_config_init,
Michael Walle63477a52021-02-14 02:17:11 +01001672 .config_aneg = at803x_config_aneg,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001673 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001674 .set_wol = at803x_set_wol,
1675 .get_wol = at803x_get_wol,
1676 .suspend = at803x_suspend,
1677 .resume = at803x_resume,
David Bauerc329e5a2021-04-15 03:26:50 +02001678 .read_page = at803x_read_page,
1679 .write_page = at803x_write_page,
David Bauerb8561502021-06-27 12:16:07 +02001680 .get_features = at803x_get_features,
Russell King06d5f342019-10-04 17:06:14 +01001681 .read_status = at803x_read_status,
Daniel Mack13a56b42014-06-18 11:01:43 +02001682 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001683 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001684 .get_tunable = at803x_get_tunable,
1685 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001686 .cable_test_start = at803x_cable_test_start,
1687 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001688}, {
David Bauer58000912020-04-17 15:41:59 +02001689 /* Qualcomm Atheros AR8032 */
1690 PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
1691 .name = "Qualcomm Atheros AR8032",
1692 .probe = at803x_probe,
1693 .remove = at803x_remove,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001694 .flags = PHY_POLL_CABLE_TEST,
David Bauer58000912020-04-17 15:41:59 +02001695 .config_init = at803x_config_init,
1696 .link_change_notify = at803x_link_change_notify,
1697 .set_wol = at803x_set_wol,
1698 .get_wol = at803x_get_wol,
1699 .suspend = at803x_suspend,
1700 .resume = at803x_resume,
1701 /* PHY_BASIC_FEATURES */
David Bauer58000912020-04-17 15:41:59 +02001702 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001703 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001704 .cable_test_start = at803x_cable_test_start,
1705 .cable_test_get_status = at803x_cable_test_get_status,
David Bauer58000912020-04-17 15:41:59 +02001706}, {
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001707 /* ATHEROS AR9331 */
1708 PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001709 .name = "Qualcomm Atheros AR9331 built-in PHY",
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001710 .suspend = at803x_suspend,
1711 .resume = at803x_resume,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001712 .flags = PHY_POLL_CABLE_TEST,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001713 /* PHY_BASIC_FEATURES */
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001714 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001715 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001716 .cable_test_start = at803x_cable_test_start,
1717 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001718 .read_status = at803x_read_status,
1719 .soft_reset = genphy_soft_reset,
1720 .config_aneg = at803x_config_aneg,
Ansuel Smith272833b2021-05-14 23:00:15 +02001721}, {
David Bauerfada2ce2021-10-06 00:54:01 +02001722 /* Qualcomm Atheros QCA9561 */
1723 PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
1724 .name = "Qualcomm Atheros QCA9561 built-in PHY",
1725 .suspend = at803x_suspend,
1726 .resume = at803x_resume,
1727 .flags = PHY_POLL_CABLE_TEST,
1728 /* PHY_BASIC_FEATURES */
1729 .config_intr = &at803x_config_intr,
1730 .handle_interrupt = at803x_handle_interrupt,
1731 .cable_test_start = at803x_cable_test_start,
1732 .cable_test_get_status = at803x_cable_test_get_status,
1733 .read_status = at803x_read_status,
1734 .soft_reset = genphy_soft_reset,
1735 .config_aneg = at803x_config_aneg,
1736}, {
Ansuel Smith272833b2021-05-14 23:00:15 +02001737 /* QCA8337 */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001738 .phy_id = QCA8337_PHY_ID,
1739 .phy_id_mask = QCA8K_PHY_ID_MASK,
1740 .name = "Qualcomm Atheros 8337 internal PHY",
Ansuel Smith272833b2021-05-14 23:00:15 +02001741 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001742 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001743 .probe = at803x_probe,
1744 .flags = PHY_IS_INTERNAL,
1745 .config_init = qca83xx_config_init,
1746 .soft_reset = genphy_soft_reset,
1747 .get_sset_count = at803x_get_sset_count,
1748 .get_strings = at803x_get_strings,
1749 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001750 .suspend = qca83xx_suspend,
1751 .resume = qca83xx_resume,
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001752}, {
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001753 /* QCA8327-A from switch QCA8327-AL1A */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001754 .phy_id = QCA8327_A_PHY_ID,
1755 .phy_id_mask = QCA8K_PHY_ID_MASK,
1756 .name = "Qualcomm Atheros 8327-A internal PHY",
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001757 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001758 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001759 .probe = at803x_probe,
1760 .flags = PHY_IS_INTERNAL,
1761 .config_init = qca83xx_config_init,
1762 .soft_reset = genphy_soft_reset,
1763 .get_sset_count = at803x_get_sset_count,
1764 .get_strings = at803x_get_strings,
1765 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001766 .suspend = qca83xx_suspend,
1767 .resume = qca83xx_resume,
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001768}, {
1769 /* QCA8327-B from switch QCA8327-BL1A */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001770 .phy_id = QCA8327_B_PHY_ID,
1771 .phy_id_mask = QCA8K_PHY_ID_MASK,
1772 .name = "Qualcomm Atheros 8327-B internal PHY",
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001773 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001774 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001775 .probe = at803x_probe,
1776 .flags = PHY_IS_INTERNAL,
1777 .config_init = qca83xx_config_init,
1778 .soft_reset = genphy_soft_reset,
1779 .get_sset_count = at803x_get_sset_count,
1780 .get_strings = at803x_get_strings,
1781 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001782 .suspend = qca83xx_suspend,
1783 .resume = qca83xx_resume,
Luo Jiedaf61732021-10-24 16:27:29 +08001784}, {
1785 /* Qualcomm QCA8081 */
1786 PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
1787 .name = "Qualcomm QCA8081",
1788 .config_intr = at803x_config_intr,
1789 .handle_interrupt = at803x_handle_interrupt,
1790 .get_tunable = at803x_get_tunable,
1791 .set_tunable = at803x_set_tunable,
1792 .set_wol = at803x_set_wol,
1793 .get_wol = at803x_get_wol,
Luo Jie765c22a2021-10-24 16:27:31 +08001794 .get_features = at803x_get_features,
Luo Jief884d442021-10-24 16:27:32 +08001795 .config_aneg = at803x_config_aneg,
Luo Jiedaf61732021-10-24 16:27:29 +08001796 .suspend = genphy_suspend,
1797 .resume = genphy_resume,
Luo Jie79c7bc02021-10-24 16:27:30 +08001798 .read_status = qca808x_read_status,
Luo Jie2acdd43f2021-10-24 16:27:35 +08001799 .config_init = qca808x_config_init,
Ansuel Smith272833b2021-05-14 23:00:15 +02001800}, };
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001801
Johan Hovold50fd7152014-11-11 19:45:59 +01001802module_phy_driver(at803x_driver);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001803
1804static struct mdio_device_id __maybe_unused atheros_tbl[] = {
Michael Walle0465d8f2020-05-22 11:53:31 +02001805 { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
1806 { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
David Bauer58000912020-04-17 15:41:59 +02001807 { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
Michael Walle0465d8f2020-05-22 11:53:31 +02001808 { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001809 { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001810 { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001811 { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
1812 { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
David Bauerfada2ce2021-10-06 00:54:01 +02001813 { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
Luo Jiedaf61732021-10-24 16:27:29 +08001814 { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001815 { }
1816};
1817
1818MODULE_DEVICE_TABLE(mdio, atheros_tbl);