blob: cecf78e6c64311f519f990645326913d15fbcc06 [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 Jiedaf61732021-10-24 16:27:29 +0800181MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver");
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000182MODULE_AUTHOR("Matus Ujhelyi");
183MODULE_LICENSE("GPL");
184
Ansuel Smith272833b2021-05-14 23:00:15 +0200185enum stat_access_type {
186 PHY,
187 MMD
188};
189
190struct at803x_hw_stat {
191 const char *string;
192 u8 reg;
193 u32 mask;
194 enum stat_access_type access_type;
195};
196
197static struct at803x_hw_stat at803x_hw_stats[] = {
198 { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
199 { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
200 { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
201};
202
Michael Walle2f664822019-11-06 23:36:14 +0100203struct at803x_priv {
204 int flags;
Michael Walle2f664822019-11-06 23:36:14 +0100205 u16 clk_25m_reg;
206 u16 clk_25m_mask;
Russell King390b4ca2021-01-14 10:45:49 +0000207 u8 smarteee_lpi_tw_1g;
208 u8 smarteee_lpi_tw_100m;
Michael Walle2f664822019-11-06 23:36:14 +0100209 struct regulator_dev *vddio_rdev;
210 struct regulator_dev *vddh_rdev;
211 struct regulator *vddio;
Ansuel Smith272833b2021-05-14 23:00:15 +0200212 u64 stats[ARRAY_SIZE(at803x_hw_stats)];
Michael Walle2f664822019-11-06 23:36:14 +0100213};
214
Daniel Mack13a56b42014-06-18 11:01:43 +0200215struct at803x_context {
216 u16 bmcr;
217 u16 advertise;
218 u16 control1000;
219 u16 int_enable;
220 u16 smart_speed;
221 u16 led_control;
222};
223
Ansuel Smith272833b2021-05-14 23:00:15 +0200224static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
225{
226 int ret;
227
228 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
229 if (ret < 0)
230 return ret;
231
232 return phy_write(phydev, AT803X_DEBUG_DATA, data);
233}
234
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100235static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
236{
237 int ret;
238
239 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
240 if (ret < 0)
241 return ret;
242
243 return phy_read(phydev, AT803X_DEBUG_DATA);
244}
245
246static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
247 u16 clear, u16 set)
248{
249 u16 val;
250 int ret;
251
252 ret = at803x_debug_reg_read(phydev, reg);
253 if (ret < 0)
254 return ret;
255
256 val = ret & 0xffff;
257 val &= ~clear;
258 val |= set;
259
260 return phy_write(phydev, AT803X_DEBUG_DATA, val);
261}
262
David Bauerc329e5a2021-04-15 03:26:50 +0200263static int at803x_write_page(struct phy_device *phydev, int page)
264{
265 int mask;
266 int set;
267
268 if (page == AT803X_PAGE_COPPER) {
269 set = AT803X_BT_BX_REG_SEL;
270 mask = 0;
271 } else {
272 set = 0;
273 mask = AT803X_BT_BX_REG_SEL;
274 }
275
276 return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set);
277}
278
279static int at803x_read_page(struct phy_device *phydev)
280{
281 int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG);
282
283 if (ccr < 0)
284 return ccr;
285
286 if (ccr & AT803X_BT_BX_REG_SEL)
287 return AT803X_PAGE_COPPER;
288
289 return AT803X_PAGE_FIBER;
290}
291
Vinod Koul6d4cd042019-02-21 15:53:15 +0530292static int at803x_enable_rx_delay(struct phy_device *phydev)
293{
Ansuel Smith67999552021-10-10 00:46:18 +0200294 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0,
Vinod Koul6d4cd042019-02-21 15:53:15 +0530295 AT803X_DEBUG_RX_CLK_DLY_EN);
296}
297
298static int at803x_enable_tx_delay(struct phy_device *phydev)
299{
Ansuel Smith67999552021-10-10 00:46:18 +0200300 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0,
Vinod Koul6d4cd042019-02-21 15:53:15 +0530301 AT803X_DEBUG_TX_CLK_DLY_EN);
302}
303
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530304static int at803x_disable_rx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100305{
Ansuel Smith67999552021-10-10 00:46:18 +0200306 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530307 AT803X_DEBUG_RX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100308}
309
Vinod Koul43f2ebd2019-02-21 15:53:14 +0530310static int at803x_disable_tx_delay(struct phy_device *phydev)
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100311{
Ansuel Smith67999552021-10-10 00:46:18 +0200312 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE,
Vinod Koulcd28d1d2019-01-21 14:43:17 +0530313 AT803X_DEBUG_TX_CLK_DLY_EN, 0);
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100314}
315
Daniel Mack13a56b42014-06-18 11:01:43 +0200316/* save relevant PHY registers to private copy */
317static void at803x_context_save(struct phy_device *phydev,
318 struct at803x_context *context)
319{
320 context->bmcr = phy_read(phydev, MII_BMCR);
321 context->advertise = phy_read(phydev, MII_ADVERTISE);
322 context->control1000 = phy_read(phydev, MII_CTRL1000);
323 context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
324 context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
325 context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
326}
327
328/* restore relevant PHY registers from private copy */
329static void at803x_context_restore(struct phy_device *phydev,
330 const struct at803x_context *context)
331{
332 phy_write(phydev, MII_BMCR, context->bmcr);
333 phy_write(phydev, MII_ADVERTISE, context->advertise);
334 phy_write(phydev, MII_CTRL1000, context->control1000);
335 phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
336 phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
337 phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
338}
339
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000340static int at803x_set_wol(struct phy_device *phydev,
341 struct ethtool_wolinfo *wol)
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000342{
343 struct net_device *ndev = phydev->attached_dev;
344 const u8 *mac;
Luo Jie7beecaf2021-10-24 16:27:27 +0800345 int ret, irq_enabled;
Luo Jiec0f0b562021-10-24 16:27:25 +0800346 unsigned int i;
347 const unsigned int offsets[] = {
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000348 AT803X_LOC_MAC_ADDR_32_47_OFFSET,
349 AT803X_LOC_MAC_ADDR_16_31_OFFSET,
350 AT803X_LOC_MAC_ADDR_0_15_OFFSET,
351 };
352
353 if (!ndev)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000354 return -ENODEV;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000355
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000356 if (wol->wolopts & WAKE_MAGIC) {
357 mac = (const u8 *) ndev->dev_addr;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000358
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000359 if (!is_valid_ether_addr(mac))
Dan Murphyfc755682017-10-10 12:42:56 -0500360 return -EINVAL;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000361
Carlo Caione0e021392019-01-25 12:35:10 +0000362 for (i = 0; i < 3; i++)
Luo Jiec0f0b562021-10-24 16:27:25 +0800363 phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
Carlo Caione0e021392019-01-25 12:35:10 +0000364 mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000365
Luo Jie7beecaf2021-10-24 16:27:27 +0800366 /* Enable WOL function */
367 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL,
368 0, AT803X_WOL_EN);
369 if (ret)
370 return ret;
371 /* Enable WOL interrupt */
Luo Jie2d4284e2021-10-24 16:27:26 +0800372 ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000373 if (ret)
374 return ret;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000375 } else {
Luo Jie7beecaf2021-10-24 16:27:27 +0800376 /* Disable WoL function */
377 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL,
378 AT803X_WOL_EN, 0);
379 if (ret)
380 return ret;
381 /* Disable WOL interrupt */
Luo Jie2d4284e2021-10-24 16:27:26 +0800382 ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000383 if (ret)
384 return ret;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000385 }
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000386
Luo Jie7beecaf2021-10-24 16:27:27 +0800387 /* Clear WOL status */
388 ret = phy_read(phydev, AT803X_INTR_STATUS);
389 if (ret < 0)
390 return ret;
391
392 /* Check if there are other interrupts except for WOL triggered when PHY is
393 * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can
394 * be passed up to the interrupt PIN.
395 */
396 irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
397 if (irq_enabled < 0)
398 return irq_enabled;
399
400 irq_enabled &= ~AT803X_INTR_ENABLE_WOL;
401 if (ret & irq_enabled && !phy_polling_mode(phydev))
402 phy_trigger_machine(phydev);
403
404 return 0;
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000405}
406
407static void at803x_get_wol(struct phy_device *phydev,
408 struct ethtool_wolinfo *wol)
409{
410 u32 value;
411
412 wol->supported = WAKE_MAGIC;
413 wol->wolopts = 0;
414
Luo Jie7beecaf2021-10-24 16:27:27 +0800415 value = phy_read_mmd(phydev, MDIO_MMD_PCS, AT803X_PHY_MMD3_WOL_CTRL);
416 if (value < 0)
417 return;
418
419 if (value & AT803X_WOL_EN)
Mugunthan V Nea13c9e2013-06-03 20:10:05 +0000420 wol->wolopts |= WAKE_MAGIC;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000421}
422
Ansuel Smith272833b2021-05-14 23:00:15 +0200423static int at803x_get_sset_count(struct phy_device *phydev)
424{
425 return ARRAY_SIZE(at803x_hw_stats);
426}
427
428static void at803x_get_strings(struct phy_device *phydev, u8 *data)
429{
430 int i;
431
432 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
433 strscpy(data + i * ETH_GSTRING_LEN,
434 at803x_hw_stats[i].string, ETH_GSTRING_LEN);
435 }
436}
437
438static u64 at803x_get_stat(struct phy_device *phydev, int i)
439{
440 struct at803x_hw_stat stat = at803x_hw_stats[i];
441 struct at803x_priv *priv = phydev->priv;
442 int val;
443 u64 ret;
444
445 if (stat.access_type == MMD)
446 val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
447 else
448 val = phy_read(phydev, stat.reg);
449
450 if (val < 0) {
451 ret = U64_MAX;
452 } else {
453 val = val & stat.mask;
454 priv->stats[i] += val;
455 ret = priv->stats[i];
456 }
457
458 return ret;
459}
460
461static void at803x_get_stats(struct phy_device *phydev,
462 struct ethtool_stats *stats, u64 *data)
463{
464 int i;
465
466 for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
467 data[i] = at803x_get_stat(phydev, i);
468}
469
Daniel Mack6229ed12013-09-21 16:53:02 +0200470static int at803x_suspend(struct phy_device *phydev)
471{
472 int value;
473 int wol_enabled;
474
Daniel Mack6229ed12013-09-21 16:53:02 +0200475 value = phy_read(phydev, AT803X_INTR_ENABLE);
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100476 wol_enabled = value & AT803X_INTR_ENABLE_WOL;
Daniel Mack6229ed12013-09-21 16:53:02 +0200477
Daniel Mack6229ed12013-09-21 16:53:02 +0200478 if (wol_enabled)
Russell Kingfea23fb2018-01-02 10:58:58 +0000479 value = BMCR_ISOLATE;
Daniel Mack6229ed12013-09-21 16:53:02 +0200480 else
Russell Kingfea23fb2018-01-02 10:58:58 +0000481 value = BMCR_PDOWN;
Daniel Mack6229ed12013-09-21 16:53:02 +0200482
Russell Kingfea23fb2018-01-02 10:58:58 +0000483 phy_modify(phydev, MII_BMCR, 0, value);
Daniel Mack6229ed12013-09-21 16:53:02 +0200484
485 return 0;
486}
487
488static int at803x_resume(struct phy_device *phydev)
489{
Russell Kingf1028522018-01-05 16:07:10 +0000490 return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
Daniel Mack6229ed12013-09-21 16:53:02 +0200491}
492
Michael Walle2f664822019-11-06 23:36:14 +0100493static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
494 unsigned int selector)
495{
496 struct phy_device *phydev = rdev_get_drvdata(rdev);
497
498 if (selector)
499 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
500 0, AT803X_DEBUG_RGMII_1V8);
501 else
502 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
503 AT803X_DEBUG_RGMII_1V8, 0);
504}
505
506static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
507{
508 struct phy_device *phydev = rdev_get_drvdata(rdev);
509 int val;
510
511 val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
512 if (val < 0)
513 return val;
514
515 return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
516}
517
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200518static const struct regulator_ops vddio_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100519 .list_voltage = regulator_list_voltage_table,
520 .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
521 .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
522};
523
524static const unsigned int vddio_voltage_table[] = {
525 1500000,
526 1800000,
527};
528
529static const struct regulator_desc vddio_desc = {
530 .name = "vddio",
531 .of_match = of_match_ptr("vddio-regulator"),
532 .n_voltages = ARRAY_SIZE(vddio_voltage_table),
533 .volt_table = vddio_voltage_table,
534 .ops = &vddio_regulator_ops,
535 .type = REGULATOR_VOLTAGE,
536 .owner = THIS_MODULE,
537};
538
Rikard Falkeborn3faaf532020-08-27 00:56:06 +0200539static const struct regulator_ops vddh_regulator_ops = {
Michael Walle2f664822019-11-06 23:36:14 +0100540};
541
542static const struct regulator_desc vddh_desc = {
543 .name = "vddh",
544 .of_match = of_match_ptr("vddh-regulator"),
545 .n_voltages = 1,
546 .fixed_uV = 2500000,
547 .ops = &vddh_regulator_ops,
548 .type = REGULATOR_VOLTAGE,
549 .owner = THIS_MODULE,
550};
551
552static int at8031_register_regulators(struct phy_device *phydev)
553{
554 struct at803x_priv *priv = phydev->priv;
555 struct device *dev = &phydev->mdio.dev;
556 struct regulator_config config = { };
557
558 config.dev = dev;
559 config.driver_data = phydev;
560
561 priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
562 if (IS_ERR(priv->vddio_rdev)) {
563 phydev_err(phydev, "failed to register VDDIO regulator\n");
564 return PTR_ERR(priv->vddio_rdev);
565 }
566
567 priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
568 if (IS_ERR(priv->vddh_rdev)) {
569 phydev_err(phydev, "failed to register VDDH regulator\n");
570 return PTR_ERR(priv->vddh_rdev);
571 }
572
573 return 0;
574}
575
Michael Walle2f664822019-11-06 23:36:14 +0100576static int at803x_parse_dt(struct phy_device *phydev)
577{
578 struct device_node *node = phydev->mdio.dev.of_node;
579 struct at803x_priv *priv = phydev->priv;
Russell King390b4ca2021-01-14 10:45:49 +0000580 u32 freq, strength, tw;
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200581 unsigned int sel;
Michael Walle2f664822019-11-06 23:36:14 +0100582 int ret;
583
584 if (!IS_ENABLED(CONFIG_OF_MDIO))
585 return 0;
586
Russell King390b4ca2021-01-14 10:45:49 +0000587 if (of_property_read_bool(node, "qca,disable-smarteee"))
588 priv->flags |= AT803X_DISABLE_SMARTEEE;
589
590 if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) {
591 if (!tw || tw > 255) {
592 phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n");
593 return -EINVAL;
594 }
595 priv->smarteee_lpi_tw_1g = tw;
596 }
597
598 if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) {
599 if (!tw || tw > 255) {
600 phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n");
601 return -EINVAL;
602 }
603 priv->smarteee_lpi_tw_100m = tw;
604 }
605
Michael Walle2f664822019-11-06 23:36:14 +0100606 ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq);
607 if (!ret) {
Michael Walle2f664822019-11-06 23:36:14 +0100608 switch (freq) {
609 case 25000000:
610 sel = AT803X_CLK_OUT_25MHZ_XTAL;
611 break;
612 case 50000000:
613 sel = AT803X_CLK_OUT_50MHZ_PLL;
614 break;
615 case 62500000:
616 sel = AT803X_CLK_OUT_62_5MHZ_PLL;
617 break;
618 case 125000000:
619 sel = AT803X_CLK_OUT_125MHZ_PLL;
620 break;
621 default:
622 phydev_err(phydev, "invalid qca,clk-out-frequency\n");
623 return -EINVAL;
624 }
625
Andrew Lunn3f2edd32020-07-07 03:49:33 +0200626 priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
627 priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100628
629 /* Fixup for the AR8030/AR8035. This chip has another mask and
630 * doesn't support the DSP reference. Eg. the lowest bit of the
631 * mask. The upper two bits select the same frequencies. Mask
632 * the lowest bit here.
633 *
634 * Warning:
635 * There was no datasheet for the AR8030 available so this is
636 * just a guess. But the AR8035 is listed as pin compatible
637 * to the AR8030 so there might be a good chance it works on
638 * the AR8030 too.
639 */
Russell King8887ca52021-07-20 14:33:49 +0100640 if (phydev->drv->phy_id == ATH8030_PHY_ID ||
641 phydev->drv->phy_id == ATH8035_PHY_ID) {
Oleksij Rempelb1f4c202020-04-01 11:57:32 +0200642 priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
643 priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
Michael Walle2f664822019-11-06 23:36:14 +0100644 }
645 }
646
647 ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
648 if (!ret) {
649 priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK;
650 switch (strength) {
651 case AR803X_STRENGTH_FULL:
652 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL;
653 break;
654 case AR803X_STRENGTH_HALF:
655 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF;
656 break;
657 case AR803X_STRENGTH_QUARTER:
658 priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER;
659 break;
660 default:
661 phydev_err(phydev, "invalid qca,clk-out-strength\n");
662 return -EINVAL;
663 }
664 }
665
Michael Walle428061f2019-11-06 23:36:15 +0100666 /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
667 * options.
668 */
Russell King8887ca52021-07-20 14:33:49 +0100669 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100670 if (of_property_read_bool(node, "qca,keep-pll-enabled"))
671 priv->flags |= AT803X_KEEP_PLL_ENABLED;
672
673 ret = at8031_register_regulators(phydev);
674 if (ret < 0)
675 return ret;
676
677 priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev,
678 "vddio");
679 if (IS_ERR(priv->vddio)) {
680 phydev_err(phydev, "failed to get VDDIO regulator\n");
681 return PTR_ERR(priv->vddio);
682 }
Michael Walle2f664822019-11-06 23:36:14 +0100683 }
684
685 return 0;
686}
687
688static int at803x_probe(struct phy_device *phydev)
689{
690 struct device *dev = &phydev->mdio.dev;
691 struct at803x_priv *priv;
David Bauerc329e5a2021-04-15 03:26:50 +0200692 int ret;
Michael Walle2f664822019-11-06 23:36:14 +0100693
694 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
695 if (!priv)
696 return -ENOMEM;
697
698 phydev->priv = priv;
699
David Bauerc329e5a2021-04-15 03:26:50 +0200700 ret = at803x_parse_dt(phydev);
701 if (ret)
702 return ret;
703
Michael Walle8f7e8762021-04-20 12:29:29 +0200704 if (priv->vddio) {
705 ret = regulator_enable(priv->vddio);
706 if (ret < 0)
707 return ret;
708 }
709
David Bauerc329e5a2021-04-15 03:26:50 +0200710 /* Some bootloaders leave the fiber page selected.
711 * Switch to the copper page, as otherwise we read
712 * the PHY capabilities from the fiber side.
713 */
Russell King8887ca52021-07-20 14:33:49 +0100714 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle8f7e8762021-04-20 12:29:29 +0200715 phy_lock_mdio_bus(phydev);
716 ret = at803x_write_page(phydev, AT803X_PAGE_COPPER);
717 phy_unlock_mdio_bus(phydev);
718 if (ret)
719 goto err;
David Bauerc329e5a2021-04-15 03:26:50 +0200720 }
721
Michael Walle8f7e8762021-04-20 12:29:29 +0200722 return 0;
723
724err:
725 if (priv->vddio)
726 regulator_disable(priv->vddio);
727
David Bauerc329e5a2021-04-15 03:26:50 +0200728 return ret;
Michael Walle2f664822019-11-06 23:36:14 +0100729}
730
Michael Walle2318ca82020-01-30 18:54:02 +0100731static void at803x_remove(struct phy_device *phydev)
732{
733 struct at803x_priv *priv = phydev->priv;
734
735 if (priv->vddio)
736 regulator_disable(priv->vddio);
737}
738
David Bauerb8561502021-06-27 12:16:07 +0200739static int at803x_get_features(struct phy_device *phydev)
740{
741 int err;
742
743 err = genphy_read_abilities(phydev);
744 if (err)
745 return err;
746
Vladimir Olteanf5621a02021-07-20 20:24:33 +0300747 if (phydev->drv->phy_id != ATH8031_PHY_ID)
David Bauerb8561502021-06-27 12:16:07 +0200748 return 0;
749
750 /* AR8031/AR8033 have different status registers
751 * for copper and fiber operation. However, the
752 * extended status register is the same for both
753 * operation modes.
754 *
755 * As a result of that, ESTATUS_1000_XFULL is set
756 * to 1 even when operating in copper TP mode.
757 *
758 * Remove this mode from the supported link modes,
759 * as this driver currently only supports copper
760 * operation.
761 */
762 linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
763 phydev->supported);
764 return 0;
765}
766
Russell King390b4ca2021-01-14 10:45:49 +0000767static int at803x_smarteee_config(struct phy_device *phydev)
768{
769 struct at803x_priv *priv = phydev->priv;
770 u16 mask = 0, val = 0;
771 int ret;
772
773 if (priv->flags & AT803X_DISABLE_SMARTEEE)
774 return phy_modify_mmd(phydev, MDIO_MMD_PCS,
775 AT803X_MMD3_SMARTEEE_CTL3,
776 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0);
777
778 if (priv->smarteee_lpi_tw_1g) {
779 mask |= 0xff00;
780 val |= priv->smarteee_lpi_tw_1g << 8;
781 }
782 if (priv->smarteee_lpi_tw_100m) {
783 mask |= 0x00ff;
784 val |= priv->smarteee_lpi_tw_100m;
785 }
786 if (!mask)
787 return 0;
788
789 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1,
790 mask, val);
791 if (ret)
792 return ret;
793
794 return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
795 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN,
796 AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
797}
798
Michael Walle2f664822019-11-06 23:36:14 +0100799static int at803x_clk_out_config(struct phy_device *phydev)
800{
801 struct at803x_priv *priv = phydev->priv;
Michael Walle2f664822019-11-06 23:36:14 +0100802
803 if (!priv->clk_25m_mask)
804 return 0;
805
Russell Kinga45c1c12021-01-10 14:54:36 +0000806 return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M,
807 priv->clk_25m_mask, priv->clk_25m_reg);
Michael Walle2f664822019-11-06 23:36:14 +0100808}
809
810static int at8031_pll_config(struct phy_device *phydev)
811{
812 struct at803x_priv *priv = phydev->priv;
813
814 /* The default after hardware reset is PLL OFF. After a soft reset, the
815 * values are retained.
816 */
817 if (priv->flags & AT803X_KEEP_PLL_ENABLED)
818 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
819 0, AT803X_DEBUG_PLL_ON);
820 else
821 return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
822 AT803X_DEBUG_PLL_ON, 0);
823}
824
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000825static int at803x_config_init(struct phy_device *phydev)
826{
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000827 int ret;
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000828
Vinod Koul6d4cd042019-02-21 15:53:15 +0530829 /* The RX and TX delay default is:
830 * after HW reset: RX delay enabled and TX delay disabled
831 * after SW reset: RX delay enabled, while TX delay retains the
832 * value before reset.
Vinod Koul6d4cd042019-02-21 15:53:15 +0530833 */
Vinod Koul6d4cd042019-02-21 15:53:15 +0530834 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100835 phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530836 ret = at803x_enable_rx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100837 else
838 ret = at803x_disable_rx_delay(phydev);
839 if (ret < 0)
840 return ret;
Martin Blumenstingl2e5f9f22016-01-15 01:55:22 +0100841
Vinod Koul6d4cd042019-02-21 15:53:15 +0530842 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
André Draszikbb0ce4c2019-08-09 12:20:25 +0100843 phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
Vinod Koul6d4cd042019-02-21 15:53:15 +0530844 ret = at803x_enable_tx_delay(phydev);
André Draszikbb0ce4c2019-08-09 12:20:25 +0100845 else
846 ret = at803x_disable_tx_delay(phydev);
Michael Walle2f664822019-11-06 23:36:14 +0100847 if (ret < 0)
848 return ret;
Mugunthan V N1ca6d1b2013-06-03 20:10:06 +0000849
Russell King390b4ca2021-01-14 10:45:49 +0000850 ret = at803x_smarteee_config(phydev);
851 if (ret < 0)
852 return ret;
853
Michael Walle2f664822019-11-06 23:36:14 +0100854 ret = at803x_clk_out_config(phydev);
855 if (ret < 0)
856 return ret;
857
Russell King8887ca52021-07-20 14:33:49 +0100858 if (phydev->drv->phy_id == ATH8031_PHY_ID) {
Michael Walle2f664822019-11-06 23:36:14 +0100859 ret = at8031_pll_config(phydev);
860 if (ret < 0)
861 return ret;
862 }
863
Russell King3c51fa52021-01-12 22:59:43 +0000864 /* Ar803x extended next page bit is enabled by default. Cisco
865 * multigig switches read this bit and attempt to negotiate 10Gbps
866 * rates even if the next page bit is disabled. This is incorrect
867 * behaviour but we still need to accommodate it. XNP is only needed
868 * for 10Gbps support, so disable XNP.
869 */
870 return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +0000871}
872
Zhao Qiang77a99392014-03-28 15:39:41 +0800873static int at803x_ack_interrupt(struct phy_device *phydev)
874{
875 int err;
876
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100877 err = phy_read(phydev, AT803X_INTR_STATUS);
Zhao Qiang77a99392014-03-28 15:39:41 +0800878
879 return (err < 0) ? err : 0;
880}
881
882static int at803x_config_intr(struct phy_device *phydev)
883{
884 int err;
885 int value;
886
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100887 value = phy_read(phydev, AT803X_INTR_ENABLE);
Zhao Qiang77a99392014-03-28 15:39:41 +0800888
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100889 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
Ioana Ciorneia3417882020-11-01 14:51:00 +0200890 /* Clear any pending interrupts */
891 err = at803x_ack_interrupt(phydev);
892 if (err)
893 return err;
894
Martin Blumenstingle6e4a552016-01-15 01:55:24 +0100895 value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
896 value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
897 value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
898 value |= AT803X_INTR_ENABLE_LINK_FAIL;
899 value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
900
901 err = phy_write(phydev, AT803X_INTR_ENABLE, value);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200902 } else {
Martin Blumenstingla46bd632016-01-15 01:55:23 +0100903 err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
Ioana Ciorneia3417882020-11-01 14:51:00 +0200904 if (err)
905 return err;
906
907 /* Clear any pending interrupts */
908 err = at803x_ack_interrupt(phydev);
909 }
Zhao Qiang77a99392014-03-28 15:39:41 +0800910
911 return err;
912}
913
Ioana Ciornei29773092020-11-01 14:50:59 +0200914static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev)
915{
916 int irq_status, int_enabled;
917
918 irq_status = phy_read(phydev, AT803X_INTR_STATUS);
919 if (irq_status < 0) {
920 phy_error(phydev);
921 return IRQ_NONE;
922 }
923
924 /* Read the current enabled interrupts */
925 int_enabled = phy_read(phydev, AT803X_INTR_ENABLE);
926 if (int_enabled < 0) {
927 phy_error(phydev);
928 return IRQ_NONE;
929 }
930
931 /* See if this was one of our enabled interrupts */
932 if (!(irq_status & int_enabled))
933 return IRQ_NONE;
934
935 phy_trigger_machine(phydev);
936
937 return IRQ_HANDLED;
938}
939
Daniel Mack13a56b42014-06-18 11:01:43 +0200940static void at803x_link_change_notify(struct phy_device *phydev)
941{
Daniel Mack13a56b42014-06-18 11:01:43 +0200942 /*
943 * Conduct a hardware reset for AT8030 every time a link loss is
944 * signalled. This is necessary to circumvent a hardware bug that
945 * occurs when the cable is unplugged while TX packets are pending
946 * in the FIFO. In such cases, the FIFO enters an error mode it
947 * cannot recover from by software.
948 */
David Bauer6110ed22019-04-17 23:59:22 +0200949 if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) {
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100950 struct at803x_context context;
Daniel Mack13a56b42014-06-18 11:01:43 +0200951
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100952 at803x_context_save(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +0200953
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100954 phy_device_reset(phydev, 1);
955 msleep(1);
956 phy_device_reset(phydev, 0);
957 msleep(1);
Daniel Mack13a56b42014-06-18 11:01:43 +0200958
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100959 at803x_context_restore(phydev, &context);
Daniel Mack13a56b42014-06-18 11:01:43 +0200960
Heiner Kallweit5c5f6262019-03-19 19:56:51 +0100961 phydev_dbg(phydev, "%s(): phy was reset\n", __func__);
Daniel Mack13a56b42014-06-18 11:01:43 +0200962 }
963}
964
Luo Jie79c7bc02021-10-24 16:27:30 +0800965static int at803x_read_specific_status(struct phy_device *phydev)
Russell King06d5f342019-10-04 17:06:14 +0100966{
Luo Jie79c7bc02021-10-24 16:27:30 +0800967 int ss;
Russell King06d5f342019-10-04 17:06:14 +0100968
969 /* Read the AT8035 PHY-Specific Status register, which indicates the
970 * speed and duplex that the PHY is actually using, irrespective of
971 * whether we are in autoneg mode or not.
972 */
973 ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
974 if (ss < 0)
975 return ss;
976
977 if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
Luo Jie79c7bc02021-10-24 16:27:30 +0800978 int sfc, speed;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +0200979
980 sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
981 if (sfc < 0)
982 return sfc;
983
Luo Jie79c7bc02021-10-24 16:27:30 +0800984 /* qca8081 takes the different bits for speed value from at803x */
985 if (phydev->drv->phy_id == QCA8081_PHY_ID)
986 speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
987 else
988 speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
989
990 switch (speed) {
Russell King06d5f342019-10-04 17:06:14 +0100991 case AT803X_SS_SPEED_10:
992 phydev->speed = SPEED_10;
993 break;
994 case AT803X_SS_SPEED_100:
995 phydev->speed = SPEED_100;
996 break;
997 case AT803X_SS_SPEED_1000:
998 phydev->speed = SPEED_1000;
999 break;
Luo Jie79c7bc02021-10-24 16:27:30 +08001000 case QCA808X_SS_SPEED_2500:
1001 phydev->speed = SPEED_2500;
1002 break;
Russell King06d5f342019-10-04 17:06:14 +01001003 }
1004 if (ss & AT803X_SS_DUPLEX)
1005 phydev->duplex = DUPLEX_FULL;
1006 else
1007 phydev->duplex = DUPLEX_HALF;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001008
Russell King06d5f342019-10-04 17:06:14 +01001009 if (ss & AT803X_SS_MDIX)
1010 phydev->mdix = ETH_TP_MDI_X;
1011 else
1012 phydev->mdix = ETH_TP_MDI;
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001013
1014 switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
1015 case AT803X_SFC_MANUAL_MDI:
1016 phydev->mdix_ctrl = ETH_TP_MDI;
1017 break;
1018 case AT803X_SFC_MANUAL_MDIX:
1019 phydev->mdix_ctrl = ETH_TP_MDI_X;
1020 break;
1021 case AT803X_SFC_AUTOMATIC_CROSSOVER:
1022 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1023 break;
1024 }
Russell King06d5f342019-10-04 17:06:14 +01001025 }
1026
Luo Jie79c7bc02021-10-24 16:27:30 +08001027 return 0;
1028}
1029
1030static int at803x_read_status(struct phy_device *phydev)
1031{
1032 int err, old_link = phydev->link;
1033
1034 /* Update the link, but return if there was an error */
1035 err = genphy_update_link(phydev);
1036 if (err)
1037 return err;
1038
1039 /* why bother the PHY if nothing can have changed */
1040 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
1041 return 0;
1042
1043 phydev->speed = SPEED_UNKNOWN;
1044 phydev->duplex = DUPLEX_UNKNOWN;
1045 phydev->pause = 0;
1046 phydev->asym_pause = 0;
1047
1048 err = genphy_read_lpa(phydev);
1049 if (err < 0)
1050 return err;
1051
1052 err = at803x_read_specific_status(phydev);
1053 if (err < 0)
1054 return err;
1055
Russell King06d5f342019-10-04 17:06:14 +01001056 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
1057 phy_resolve_aneg_pause(phydev);
1058
1059 return 0;
1060}
1061
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001062static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
1063{
1064 u16 val;
1065
1066 switch (ctrl) {
1067 case ETH_TP_MDI:
1068 val = AT803X_SFC_MANUAL_MDI;
1069 break;
1070 case ETH_TP_MDI_X:
1071 val = AT803X_SFC_MANUAL_MDIX;
1072 break;
1073 case ETH_TP_MDI_AUTO:
1074 val = AT803X_SFC_AUTOMATIC_CROSSOVER;
1075 break;
1076 default:
1077 return 0;
1078 }
1079
1080 return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
1081 AT803X_SFC_MDI_CROSSOVER_MODE_M,
1082 FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
1083}
1084
1085static int at803x_config_aneg(struct phy_device *phydev)
1086{
1087 int ret;
1088
1089 ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
1090 if (ret < 0)
1091 return ret;
1092
1093 /* Changes of the midx bits are disruptive to the normal operation;
1094 * therefore any changes to these registers must be followed by a
1095 * software reset to take effect.
1096 */
1097 if (ret == 1) {
1098 ret = genphy_soft_reset(phydev);
1099 if (ret < 0)
1100 return ret;
1101 }
1102
1103 return genphy_config_aneg(phydev);
1104}
1105
Michael Wallecde0f4f2020-04-28 23:15:02 +02001106static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
1107{
1108 int val;
1109
1110 val = phy_read(phydev, AT803X_SMART_SPEED);
1111 if (val < 0)
1112 return val;
1113
1114 if (val & AT803X_SMART_SPEED_ENABLE)
1115 *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
1116 else
1117 *d = DOWNSHIFT_DEV_DISABLE;
1118
1119 return 0;
1120}
1121
1122static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
1123{
1124 u16 mask, set;
1125 int ret;
1126
1127 switch (cnt) {
1128 case DOWNSHIFT_DEV_DEFAULT_COUNT:
1129 cnt = AT803X_DEFAULT_DOWNSHIFT;
1130 fallthrough;
1131 case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
1132 set = AT803X_SMART_SPEED_ENABLE |
1133 AT803X_SMART_SPEED_BYPASS_TIMER |
1134 FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
1135 mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
1136 break;
1137 case DOWNSHIFT_DEV_DISABLE:
1138 set = 0;
1139 mask = AT803X_SMART_SPEED_ENABLE |
1140 AT803X_SMART_SPEED_BYPASS_TIMER;
1141 break;
1142 default:
1143 return -EINVAL;
1144 }
1145
1146 ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);
1147
1148 /* After changing the smart speed settings, we need to perform a
1149 * software reset, use phy_init_hw() to make sure we set the
1150 * reapply any values which might got lost during software reset.
1151 */
1152 if (ret == 1)
1153 ret = phy_init_hw(phydev);
1154
1155 return ret;
1156}
1157
1158static int at803x_get_tunable(struct phy_device *phydev,
1159 struct ethtool_tunable *tuna, void *data)
1160{
1161 switch (tuna->id) {
1162 case ETHTOOL_PHY_DOWNSHIFT:
1163 return at803x_get_downshift(phydev, data);
1164 default:
1165 return -EOPNOTSUPP;
1166 }
1167}
1168
1169static int at803x_set_tunable(struct phy_device *phydev,
1170 struct ethtool_tunable *tuna, const void *data)
1171{
1172 switch (tuna->id) {
1173 case ETHTOOL_PHY_DOWNSHIFT:
1174 return at803x_set_downshift(phydev, *(const u8 *)data);
1175 default:
1176 return -EOPNOTSUPP;
1177 }
1178}
1179
Michael Walle6cb75762020-05-13 22:38:07 +02001180static int at803x_cable_test_result_trans(u16 status)
1181{
1182 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1183 case AT803X_CDT_STATUS_STAT_NORMAL:
1184 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
1185 case AT803X_CDT_STATUS_STAT_SHORT:
1186 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
1187 case AT803X_CDT_STATUS_STAT_OPEN:
1188 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
1189 case AT803X_CDT_STATUS_STAT_FAIL:
1190 default:
1191 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
1192 }
1193}
1194
1195static bool at803x_cdt_test_failed(u16 status)
1196{
1197 return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) ==
1198 AT803X_CDT_STATUS_STAT_FAIL;
1199}
1200
1201static bool at803x_cdt_fault_length_valid(u16 status)
1202{
1203 switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
1204 case AT803X_CDT_STATUS_STAT_OPEN:
1205 case AT803X_CDT_STATUS_STAT_SHORT:
1206 return true;
1207 }
1208 return false;
1209}
1210
1211static int at803x_cdt_fault_length(u16 status)
1212{
1213 int dt;
1214
1215 /* According to the datasheet the distance to the fault is
1216 * DELTA_TIME * 0.824 meters.
1217 *
1218 * The author suspect the correct formula is:
1219 *
1220 * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2
1221 *
1222 * where c is the speed of light, VF is the velocity factor of
1223 * the twisted pair cable, 125MHz the counter frequency and
1224 * we need to divide by 2 because the hardware will measure the
1225 * round trip time to the fault and back to the PHY.
1226 *
1227 * With a VF of 0.69 we get the factor 0.824 mentioned in the
1228 * datasheet.
1229 */
1230 dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
1231
1232 return (dt * 824) / 10;
1233}
1234
1235static int at803x_cdt_start(struct phy_device *phydev, int pair)
1236{
1237 u16 cdt;
1238
1239 cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
1240 AT803X_CDT_ENABLE_TEST;
1241
1242 return phy_write(phydev, AT803X_CDT, cdt);
1243}
1244
1245static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
1246{
1247 int val, ret;
1248
1249 /* One test run takes about 25ms */
1250 ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
1251 !(val & AT803X_CDT_ENABLE_TEST),
1252 30000, 100000, true);
1253
1254 return ret < 0 ? ret : 0;
1255}
1256
1257static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
1258{
1259 static const int ethtool_pair[] = {
1260 ETHTOOL_A_CABLE_PAIR_A,
1261 ETHTOOL_A_CABLE_PAIR_B,
1262 ETHTOOL_A_CABLE_PAIR_C,
1263 ETHTOOL_A_CABLE_PAIR_D,
1264 };
1265 int ret, val;
1266
1267 ret = at803x_cdt_start(phydev, pair);
1268 if (ret)
1269 return ret;
1270
1271 ret = at803x_cdt_wait_for_completion(phydev);
1272 if (ret)
1273 return ret;
1274
1275 val = phy_read(phydev, AT803X_CDT_STATUS);
1276 if (val < 0)
1277 return val;
1278
1279 if (at803x_cdt_test_failed(val))
1280 return 0;
1281
1282 ethnl_cable_test_result(phydev, ethtool_pair[pair],
1283 at803x_cable_test_result_trans(val));
1284
1285 if (at803x_cdt_fault_length_valid(val))
1286 ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
1287 at803x_cdt_fault_length(val));
1288
1289 return 1;
1290}
1291
1292static int at803x_cable_test_get_status(struct phy_device *phydev,
1293 bool *finished)
1294{
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001295 unsigned long pair_mask;
Michael Walle6cb75762020-05-13 22:38:07 +02001296 int retries = 20;
1297 int pair, ret;
1298
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001299 if (phydev->phy_id == ATH9331_PHY_ID ||
David Bauerfada2ce2021-10-06 00:54:01 +02001300 phydev->phy_id == ATH8032_PHY_ID ||
1301 phydev->phy_id == QCA9561_PHY_ID)
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001302 pair_mask = 0x3;
1303 else
1304 pair_mask = 0xf;
1305
Michael Walle6cb75762020-05-13 22:38:07 +02001306 *finished = false;
1307
1308 /* According to the datasheet the CDT can be performed when
1309 * there is no link partner or when the link partner is
1310 * auto-negotiating. Starting the test will restart the AN
1311 * automatically. It seems that doing this repeatedly we will
1312 * get a slot where our link partner won't disturb our
1313 * measurement.
1314 */
1315 while (pair_mask && retries--) {
1316 for_each_set_bit(pair, &pair_mask, 4) {
1317 ret = at803x_cable_test_one_pair(phydev, pair);
1318 if (ret < 0)
1319 return ret;
1320 if (ret)
1321 clear_bit(pair, &pair_mask);
1322 }
1323 if (pair_mask)
1324 msleep(250);
1325 }
1326
1327 *finished = true;
1328
1329 return 0;
1330}
1331
1332static int at803x_cable_test_start(struct phy_device *phydev)
1333{
1334 /* Enable auto-negotiation, but advertise no capabilities, no link
1335 * will be established. A restart of the auto-negotiation is not
1336 * required, because the cable test will automatically break the link.
1337 */
1338 phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
1339 phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001340 if (phydev->phy_id != ATH9331_PHY_ID &&
David Bauerfada2ce2021-10-06 00:54:01 +02001341 phydev->phy_id != ATH8032_PHY_ID &&
1342 phydev->phy_id != QCA9561_PHY_ID)
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001343 phy_write(phydev, MII_CTRL1000, 0);
Michael Walle6cb75762020-05-13 22:38:07 +02001344
1345 /* we do all the (time consuming) work later */
1346 return 0;
1347}
1348
Ansuel Smith272833b2021-05-14 23:00:15 +02001349static int qca83xx_config_init(struct phy_device *phydev)
1350{
1351 u8 switch_revision;
1352
1353 switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
1354
1355 switch (switch_revision) {
1356 case 1:
1357 /* For 100M waveform */
Ansuel Smith67999552021-10-10 00:46:18 +02001358 at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
Ansuel Smith272833b2021-05-14 23:00:15 +02001359 /* Turn on Gigabit clock */
Ansuel Smith67999552021-10-10 00:46:18 +02001360 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
Ansuel Smith272833b2021-05-14 23:00:15 +02001361 break;
1362
1363 case 2:
1364 phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
1365 fallthrough;
1366 case 4:
1367 phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
Ansuel Smith67999552021-10-10 00:46:18 +02001368 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
1369 at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
Ansuel Smith272833b2021-05-14 23:00:15 +02001370 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
1371 break;
1372 }
1373
Ansuel Smith1ca83112021-10-10 00:46:16 +02001374 /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
1375 * Disable on init and enable only with 100m speed following
1376 * qca original source code.
1377 */
1378 if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
1379 phydev->drv->phy_id == QCA8327_B_PHY_ID)
Ansuel Smith67999552021-10-10 00:46:18 +02001380 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001381 QCA8327_DEBUG_MANU_CTRL_EN, 0);
1382
Ansuel Smith9d1c29b2021-10-10 00:46:17 +02001383 /* Following original QCA sourcecode set port to prefer master */
1384 phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
1385
Ansuel Smith272833b2021-05-14 23:00:15 +02001386 return 0;
1387}
1388
Ansuel Smith1ca83112021-10-10 00:46:16 +02001389static void qca83xx_link_change_notify(struct phy_device *phydev)
1390{
1391 /* QCA8337 doesn't require DAC Amplitude adjustement */
1392 if (phydev->drv->phy_id == QCA8337_PHY_ID)
1393 return;
1394
1395 /* Set DAC Amplitude adjustment to +6% for 100m on link running */
1396 if (phydev->state == PHY_RUNNING) {
1397 if (phydev->speed == SPEED_100)
Ansuel Smith67999552021-10-10 00:46:18 +02001398 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001399 QCA8327_DEBUG_MANU_CTRL_EN,
1400 QCA8327_DEBUG_MANU_CTRL_EN);
1401 } else {
1402 /* Reset DAC Amplitude adjustment */
Ansuel Smith67999552021-10-10 00:46:18 +02001403 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
Ansuel Smith1ca83112021-10-10 00:46:16 +02001404 QCA8327_DEBUG_MANU_CTRL_EN, 0);
1405 }
1406}
1407
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001408static int qca83xx_resume(struct phy_device *phydev)
1409{
1410 int ret, val;
1411
1412 /* Skip reset if not suspended */
1413 if (!phydev->suspended)
1414 return 0;
1415
1416 /* Reinit the port, reset values set by suspend */
1417 qca83xx_config_init(phydev);
1418
1419 /* Reset the port on port resume */
1420 phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
1421
1422 /* On resume from suspend the switch execute a reset and
1423 * restart auto-negotiation. Wait for reset to complete.
1424 */
1425 ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
1426 50000, 600000, true);
1427 if (ret)
1428 return ret;
1429
1430 msleep(1);
1431
1432 return 0;
1433}
1434
1435static int qca83xx_suspend(struct phy_device *phydev)
1436{
1437 u16 mask = 0;
1438
1439 /* Only QCA8337 support actual suspend.
1440 * QCA8327 cause port unreliability when phy suspend
1441 * is set.
1442 */
1443 if (phydev->drv->phy_id == QCA8337_PHY_ID) {
1444 genphy_suspend(phydev);
1445 } else {
1446 mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
1447 phy_modify(phydev, MII_BMCR, mask, 0);
1448 }
1449
Ansuel Smith67999552021-10-10 00:46:18 +02001450 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001451 AT803X_DEBUG_GATE_CLK_IN1000, 0);
1452
1453 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
1454 AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
1455 AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
1456
1457 return 0;
1458}
1459
Luo Jie79c7bc02021-10-24 16:27:30 +08001460static int qca808x_read_status(struct phy_device *phydev)
1461{
1462 int ret;
1463
1464 ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
1465 if (ret < 0)
1466 return ret;
1467
1468 linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
1469 ret & MDIO_AN_10GBT_STAT_LP2_5G);
1470
1471 ret = genphy_read_status(phydev);
1472 if (ret)
1473 return ret;
1474
1475 ret = at803x_read_specific_status(phydev);
1476 if (ret < 0)
1477 return ret;
1478
1479 if (phydev->link && phydev->speed == SPEED_2500)
1480 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
1481 else
1482 phydev->interface = PHY_INTERFACE_MODE_SMII;
1483
1484 return 0;
1485}
1486
Mugunthan V N317420a2013-06-03 20:10:04 +00001487static struct phy_driver at803x_driver[] = {
1488{
Michael Walle96c36712019-11-06 23:36:16 +01001489 /* Qualcomm Atheros AR8035 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001490 PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001491 .name = "Qualcomm Atheros AR8035",
Michael Walle6cb75762020-05-13 22:38:07 +02001492 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001493 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001494 .remove = at803x_remove,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001495 .config_aneg = at803x_config_aneg,
Daniel Mack13a56b42014-06-18 11:01:43 +02001496 .config_init = at803x_config_init,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001497 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001498 .set_wol = at803x_set_wol,
1499 .get_wol = at803x_get_wol,
1500 .suspend = at803x_suspend,
1501 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001502 /* PHY_GBIT_FEATURES */
Russell King06d5f342019-10-04 17:06:14 +01001503 .read_status = at803x_read_status,
Måns Rullgård0eae5982015-11-12 17:40:20 +00001504 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001505 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001506 .get_tunable = at803x_get_tunable,
1507 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001508 .cable_test_start = at803x_cable_test_start,
1509 .cable_test_get_status = at803x_cable_test_get_status,
Mugunthan V N317420a2013-06-03 20:10:04 +00001510}, {
Michael Walle96c36712019-11-06 23:36:16 +01001511 /* Qualcomm Atheros AR8030 */
Daniel Mack13a56b42014-06-18 11:01:43 +02001512 .phy_id = ATH8030_PHY_ID,
Michael Walle96c36712019-11-06 23:36:16 +01001513 .name = "Qualcomm Atheros AR8030",
Michael Walle0465d8f2020-05-22 11:53:31 +02001514 .phy_id_mask = AT8030_PHY_ID_MASK,
Michael Walle2f664822019-11-06 23:36:14 +01001515 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001516 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001517 .config_init = at803x_config_init,
1518 .link_change_notify = at803x_link_change_notify,
1519 .set_wol = at803x_set_wol,
1520 .get_wol = at803x_get_wol,
1521 .suspend = at803x_suspend,
1522 .resume = at803x_resume,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001523 /* PHY_BASIC_FEATURES */
Måns Rullgård0eae5982015-11-12 17:40:20 +00001524 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001525 .handle_interrupt = at803x_handle_interrupt,
Mugunthan V N05d7cce2013-06-03 20:10:07 +00001526}, {
Michael Walle96c36712019-11-06 23:36:16 +01001527 /* Qualcomm Atheros AR8031/AR8033 */
Michael Walle0465d8f2020-05-22 11:53:31 +02001528 PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001529 .name = "Qualcomm Atheros AR8031/AR8033",
Michael Walle6cb75762020-05-13 22:38:07 +02001530 .flags = PHY_POLL_CABLE_TEST,
Michael Walle2f664822019-11-06 23:36:14 +01001531 .probe = at803x_probe,
Michael Walle2318ca82020-01-30 18:54:02 +01001532 .remove = at803x_remove,
Daniel Mack13a56b42014-06-18 11:01:43 +02001533 .config_init = at803x_config_init,
Michael Walle63477a52021-02-14 02:17:11 +01001534 .config_aneg = at803x_config_aneg,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001535 .soft_reset = genphy_soft_reset,
Daniel Mack13a56b42014-06-18 11:01:43 +02001536 .set_wol = at803x_set_wol,
1537 .get_wol = at803x_get_wol,
1538 .suspend = at803x_suspend,
1539 .resume = at803x_resume,
David Bauerc329e5a2021-04-15 03:26:50 +02001540 .read_page = at803x_read_page,
1541 .write_page = at803x_write_page,
David Bauerb8561502021-06-27 12:16:07 +02001542 .get_features = at803x_get_features,
Russell King06d5f342019-10-04 17:06:14 +01001543 .read_status = at803x_read_status,
Daniel Mack13a56b42014-06-18 11:01:43 +02001544 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001545 .handle_interrupt = at803x_handle_interrupt,
Michael Wallecde0f4f2020-04-28 23:15:02 +02001546 .get_tunable = at803x_get_tunable,
1547 .set_tunable = at803x_set_tunable,
Michael Walle6cb75762020-05-13 22:38:07 +02001548 .cable_test_start = at803x_cable_test_start,
1549 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001550}, {
David Bauer58000912020-04-17 15:41:59 +02001551 /* Qualcomm Atheros AR8032 */
1552 PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
1553 .name = "Qualcomm Atheros AR8032",
1554 .probe = at803x_probe,
1555 .remove = at803x_remove,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001556 .flags = PHY_POLL_CABLE_TEST,
David Bauer58000912020-04-17 15:41:59 +02001557 .config_init = at803x_config_init,
1558 .link_change_notify = at803x_link_change_notify,
1559 .set_wol = at803x_set_wol,
1560 .get_wol = at803x_get_wol,
1561 .suspend = at803x_suspend,
1562 .resume = at803x_resume,
1563 /* PHY_BASIC_FEATURES */
David Bauer58000912020-04-17 15:41:59 +02001564 .config_intr = at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001565 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001566 .cable_test_start = at803x_cable_test_start,
1567 .cable_test_get_status = at803x_cable_test_get_status,
David Bauer58000912020-04-17 15:41:59 +02001568}, {
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001569 /* ATHEROS AR9331 */
1570 PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
Michael Walle96c36712019-11-06 23:36:16 +01001571 .name = "Qualcomm Atheros AR9331 built-in PHY",
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001572 .suspend = at803x_suspend,
1573 .resume = at803x_resume,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001574 .flags = PHY_POLL_CABLE_TEST,
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001575 /* PHY_BASIC_FEATURES */
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001576 .config_intr = &at803x_config_intr,
Ioana Ciornei29773092020-11-01 14:50:59 +02001577 .handle_interrupt = at803x_handle_interrupt,
Oleksij Rempeldc0f3ed2020-05-27 07:08:43 +02001578 .cable_test_start = at803x_cable_test_start,
1579 .cable_test_get_status = at803x_cable_test_get_status,
Oleksij Rempel7dce80c2020-07-19 10:05:30 +02001580 .read_status = at803x_read_status,
1581 .soft_reset = genphy_soft_reset,
1582 .config_aneg = at803x_config_aneg,
Ansuel Smith272833b2021-05-14 23:00:15 +02001583}, {
David Bauerfada2ce2021-10-06 00:54:01 +02001584 /* Qualcomm Atheros QCA9561 */
1585 PHY_ID_MATCH_EXACT(QCA9561_PHY_ID),
1586 .name = "Qualcomm Atheros QCA9561 built-in PHY",
1587 .suspend = at803x_suspend,
1588 .resume = at803x_resume,
1589 .flags = PHY_POLL_CABLE_TEST,
1590 /* PHY_BASIC_FEATURES */
1591 .config_intr = &at803x_config_intr,
1592 .handle_interrupt = at803x_handle_interrupt,
1593 .cable_test_start = at803x_cable_test_start,
1594 .cable_test_get_status = at803x_cable_test_get_status,
1595 .read_status = at803x_read_status,
1596 .soft_reset = genphy_soft_reset,
1597 .config_aneg = at803x_config_aneg,
1598}, {
Ansuel Smith272833b2021-05-14 23:00:15 +02001599 /* QCA8337 */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001600 .phy_id = QCA8337_PHY_ID,
1601 .phy_id_mask = QCA8K_PHY_ID_MASK,
1602 .name = "Qualcomm Atheros 8337 internal PHY",
Ansuel Smith272833b2021-05-14 23:00:15 +02001603 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001604 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001605 .probe = at803x_probe,
1606 .flags = PHY_IS_INTERNAL,
1607 .config_init = qca83xx_config_init,
1608 .soft_reset = genphy_soft_reset,
1609 .get_sset_count = at803x_get_sset_count,
1610 .get_strings = at803x_get_strings,
1611 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001612 .suspend = qca83xx_suspend,
1613 .resume = qca83xx_resume,
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001614}, {
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001615 /* QCA8327-A from switch QCA8327-AL1A */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001616 .phy_id = QCA8327_A_PHY_ID,
1617 .phy_id_mask = QCA8K_PHY_ID_MASK,
1618 .name = "Qualcomm Atheros 8327-A internal PHY",
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001619 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001620 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001621 .probe = at803x_probe,
1622 .flags = PHY_IS_INTERNAL,
1623 .config_init = qca83xx_config_init,
1624 .soft_reset = genphy_soft_reset,
1625 .get_sset_count = at803x_get_sset_count,
1626 .get_strings = at803x_get_strings,
1627 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001628 .suspend = qca83xx_suspend,
1629 .resume = qca83xx_resume,
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001630}, {
1631 /* QCA8327-B from switch QCA8327-BL1A */
Ansuel Smithd44fd862021-09-19 18:28:17 +02001632 .phy_id = QCA8327_B_PHY_ID,
1633 .phy_id_mask = QCA8K_PHY_ID_MASK,
1634 .name = "Qualcomm Atheros 8327-B internal PHY",
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001635 /* PHY_GBIT_FEATURES */
Ansuel Smith1ca83112021-10-10 00:46:16 +02001636 .link_change_notify = qca83xx_link_change_notify,
Ansuel Smithd44fd862021-09-19 18:28:17 +02001637 .probe = at803x_probe,
1638 .flags = PHY_IS_INTERNAL,
1639 .config_init = qca83xx_config_init,
1640 .soft_reset = genphy_soft_reset,
1641 .get_sset_count = at803x_get_sset_count,
1642 .get_strings = at803x_get_strings,
1643 .get_stats = at803x_get_stats,
Ansuel Smithba3c01e2021-10-10 00:46:15 +02001644 .suspend = qca83xx_suspend,
1645 .resume = qca83xx_resume,
Luo Jiedaf61732021-10-24 16:27:29 +08001646}, {
1647 /* Qualcomm QCA8081 */
1648 PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
1649 .name = "Qualcomm QCA8081",
1650 .config_intr = at803x_config_intr,
1651 .handle_interrupt = at803x_handle_interrupt,
1652 .get_tunable = at803x_get_tunable,
1653 .set_tunable = at803x_set_tunable,
1654 .set_wol = at803x_set_wol,
1655 .get_wol = at803x_get_wol,
1656 .suspend = genphy_suspend,
1657 .resume = genphy_resume,
Luo Jie79c7bc02021-10-24 16:27:30 +08001658 .read_status = qca808x_read_status,
Ansuel Smith272833b2021-05-14 23:00:15 +02001659}, };
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001660
Johan Hovold50fd7152014-11-11 19:45:59 +01001661module_phy_driver(at803x_driver);
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001662
1663static struct mdio_device_id __maybe_unused atheros_tbl[] = {
Michael Walle0465d8f2020-05-22 11:53:31 +02001664 { ATH8030_PHY_ID, AT8030_PHY_ID_MASK },
1665 { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) },
David Bauer58000912020-04-17 15:41:59 +02001666 { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
Michael Walle0465d8f2020-05-22 11:53:31 +02001667 { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
Oleksij Rempel7908d2c2019-10-03 10:21:12 +02001668 { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
Ansuel Smith0ccf8512021-09-14 14:33:45 +02001669 { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
Ansuel Smithb4df02b2021-09-19 18:28:15 +02001670 { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
1671 { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
David Bauerfada2ce2021-10-06 00:54:01 +02001672 { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
Luo Jiedaf61732021-10-24 16:27:29 +08001673 { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
Matus Ujhelyi0ca71112012-10-14 19:07:16 +00001674 { }
1675};
1676
1677MODULE_DEVICE_TABLE(mdio, atheros_tbl);