blob: a7ebcdab415b5fae392410ae87ce06f070ce7f66 [file] [log] [blame]
Andrew Lunna2443fd2019-01-21 19:05:50 +01001// SPDX-License-Identifier: GPL-2.0+
David J. Choid0507002010-04-29 06:12:41 +00002/*
3 * drivers/net/phy/micrel.c
4 *
5 * Driver for Micrel PHYs
6 *
7 * Author: David J. Choi
8 *
David J. Choi7ab59dc2013-01-23 14:05:15 +00009 * Copyright (c) 2010-2013 Micrel, Inc.
Johan Hovoldee0dc2f2014-11-19 12:59:23 +010010 * Copyright (c) 2014 Johan Hovold <johan@kernel.org>
David J. Choid0507002010-04-29 06:12:41 +000011 *
David J. Choi7ab59dc2013-01-23 14:05:15 +000012 * Support : Micrel Phys:
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -040013 * Giga phys: ksz9021, ksz9031, ksz9131
David J. Choi7ab59dc2013-01-23 14:05:15 +000014 * 100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
15 * ksz8021, ksz8031, ksz8051,
16 * ksz8081, ksz8091,
17 * ksz8061,
18 * Switch : ksz8873, ksz886x
Woojung Huhfc3973a2017-05-31 20:19:13 +000019 * ksz9477
David J. Choid0507002010-04-29 06:12:41 +000020 */
21
Oleksij Rempelbcf34402020-04-22 09:21:37 +020022#include <linux/bitfield.h>
Oleksij Rempel49011e02021-06-14 06:31:25 +020023#include <linux/ethtool_netlink.h>
David J. Choid0507002010-04-29 06:12:41 +000024#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/phy.h>
Baruch Siachd606ef32011-02-14 02:05:33 +000027#include <linux/micrel_phy.h>
Sean Cross954c3962013-08-21 01:46:12 +000028#include <linux/of.h>
Sascha Hauer1fadee02014-10-10 09:48:05 +020029#include <linux/clk.h>
Oleksij Rempel6110dff2020-04-03 09:53:25 +020030#include <linux/delay.h>
David J. Choid0507002010-04-29 06:12:41 +000031
Marek Vasut212ea992012-09-23 16:58:49 +000032/* Operation Mode Strap Override */
33#define MII_KSZPHY_OMSO 0x16
Antoine Tenart7a1d8392019-04-26 18:41:23 +020034#define KSZPHY_OMSO_FACTORY_TEST BIT(15)
Johan Hovold00aee092014-11-11 20:00:09 +010035#define KSZPHY_OMSO_B_CAST_OFF BIT(9)
Sylvain Rochet2b0ba962015-02-13 21:35:33 +010036#define KSZPHY_OMSO_NAND_TREE_ON BIT(5)
Johan Hovold00aee092014-11-11 20:00:09 +010037#define KSZPHY_OMSO_RMII_OVERRIDE BIT(1)
38#define KSZPHY_OMSO_MII_OVERRIDE BIT(0)
Marek Vasut212ea992012-09-23 16:58:49 +000039
Choi, David51f932c2010-06-28 15:23:41 +000040/* general Interrupt control/status reg in vendor specific block. */
41#define MII_KSZPHY_INTCS 0x1B
Oleksij Rempel0033f892021-06-14 06:31:20 +020042#define KSZPHY_INTCS_JABBER BIT(15)
43#define KSZPHY_INTCS_RECEIVE_ERR BIT(14)
44#define KSZPHY_INTCS_PAGE_RECEIVE BIT(13)
45#define KSZPHY_INTCS_PARELLEL BIT(12)
46#define KSZPHY_INTCS_LINK_PARTNER_ACK BIT(11)
47#define KSZPHY_INTCS_LINK_DOWN BIT(10)
48#define KSZPHY_INTCS_REMOTE_FAULT BIT(9)
49#define KSZPHY_INTCS_LINK_UP BIT(8)
50#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\
Choi, David51f932c2010-06-28 15:23:41 +000051 KSZPHY_INTCS_LINK_DOWN)
Oleksij Rempel0033f892021-06-14 06:31:20 +020052#define KSZPHY_INTCS_LINK_DOWN_STATUS BIT(2)
53#define KSZPHY_INTCS_LINK_UP_STATUS BIT(0)
54#define KSZPHY_INTCS_STATUS (KSZPHY_INTCS_LINK_DOWN_STATUS |\
Ioana Ciornei59ca4e52020-11-23 17:38:09 +020055 KSZPHY_INTCS_LINK_UP_STATUS)
Choi, David51f932c2010-06-28 15:23:41 +000056
Oleksij Rempel49011e02021-06-14 06:31:25 +020057/* LinkMD Control/Status */
58#define KSZ8081_LMD 0x1d
59#define KSZ8081_LMD_ENABLE_TEST BIT(15)
60#define KSZ8081_LMD_STAT_NORMAL 0
61#define KSZ8081_LMD_STAT_OPEN 1
62#define KSZ8081_LMD_STAT_SHORT 2
63#define KSZ8081_LMD_STAT_FAIL 3
64#define KSZ8081_LMD_STAT_MASK GENMASK(14, 13)
65/* Short cable (<10 meter) has been detected by LinkMD */
66#define KSZ8081_LMD_SHORT_INDICATOR BIT(12)
67#define KSZ8081_LMD_DELTA_TIME_MASK GENMASK(8, 0)
68
Divya Kopperab3ec7242021-12-21 16:52:17 +053069/* Lan8814 general Interrupt control/status reg in GPHY specific block. */
70#define LAN8814_INTC 0x18
71#define LAN8814_INTS 0x1B
72
73#define LAN8814_INT_LINK_DOWN BIT(2)
74#define LAN8814_INT_LINK_UP BIT(0)
75#define LAN8814_INT_LINK (LAN8814_INT_LINK_UP |\
76 LAN8814_INT_LINK_DOWN)
77
78#define LAN8814_INTR_CTRL_REG 0x34
79#define LAN8814_INTR_CTRL_REG_POLARITY BIT(1)
80#define LAN8814_INTR_CTRL_REG_INTR_ENABLE BIT(0)
81
Johan Hovold5a167782014-11-11 20:00:14 +010082/* PHY Control 1 */
Oleksij Rempel0033f892021-06-14 06:31:20 +020083#define MII_KSZPHY_CTRL_1 0x1e
Oleksij Rempelf873f112021-06-14 06:31:22 +020084#define KSZ8081_CTRL1_MDIX_STAT BIT(4)
Johan Hovold5a167782014-11-11 20:00:14 +010085
86/* PHY Control 2 / PHY Control (if no PHY Control 1) */
Oleksij Rempel0033f892021-06-14 06:31:20 +020087#define MII_KSZPHY_CTRL_2 0x1f
88#define MII_KSZPHY_CTRL MII_KSZPHY_CTRL_2
Choi, David51f932c2010-06-28 15:23:41 +000089/* bitmap of PHY register to set interrupt mode */
Oleksij Rempelf873f112021-06-14 06:31:22 +020090#define KSZ8081_CTRL2_HP_MDIX BIT(15)
91#define KSZ8081_CTRL2_MDI_MDI_X_SELECT BIT(14)
92#define KSZ8081_CTRL2_DISABLE_AUTO_MDIX BIT(13)
93#define KSZ8081_CTRL2_FORCE_LINK BIT(11)
94#define KSZ8081_CTRL2_POWER_SAVING BIT(10)
Johan Hovold00aee092014-11-11 20:00:09 +010095#define KSZPHY_CTRL_INT_ACTIVE_HIGH BIT(9)
Johan Hovold63f44b22014-11-19 12:59:18 +010096#define KSZPHY_RMII_REF_CLK_SEL BIT(7)
Choi, David51f932c2010-06-28 15:23:41 +000097
Sean Cross954c3962013-08-21 01:46:12 +000098/* Write/read to/from extended registers */
Oleksij Rempel0033f892021-06-14 06:31:20 +020099#define MII_KSZPHY_EXTREG 0x0b
100#define KSZPHY_EXTREG_WRITE 0x8000
Sean Cross954c3962013-08-21 01:46:12 +0000101
Oleksij Rempel0033f892021-06-14 06:31:20 +0200102#define MII_KSZPHY_EXTREG_WRITE 0x0c
103#define MII_KSZPHY_EXTREG_READ 0x0d
Sean Cross954c3962013-08-21 01:46:12 +0000104
105/* Extended registers */
Oleksij Rempel0033f892021-06-14 06:31:20 +0200106#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW 0x104
107#define MII_KSZPHY_RX_DATA_PAD_SKEW 0x105
108#define MII_KSZPHY_TX_DATA_PAD_SKEW 0x106
Sean Cross954c3962013-08-21 01:46:12 +0000109
110#define PS_TO_REG 200
111
Andrew Lunn2b2427d2015-12-30 16:28:27 +0100112struct kszphy_hw_stat {
113 const char *string;
114 u8 reg;
115 u8 bits;
116};
117
118static struct kszphy_hw_stat kszphy_hw_stats[] = {
119 { "phy_receive_errors", 21, 16},
120 { "phy_idle_errors", 10, 8 },
121};
122
Johan Hovolde6a423a2014-11-19 12:59:15 +0100123struct kszphy_type {
124 u32 led_mode_reg;
Johan Hovoldc6f95752014-11-19 12:59:22 +0100125 u16 interrupt_level_mask;
Johan Hovold0f959032014-11-19 12:59:17 +0100126 bool has_broadcast_disable;
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100127 bool has_nand_tree_disable;
Johan Hovold63f44b22014-11-19 12:59:18 +0100128 bool has_rmii_ref_clk_sel;
Johan Hovolde6a423a2014-11-19 12:59:15 +0100129};
130
131struct kszphy_priv {
132 const struct kszphy_type *type;
Johan Hovolde7a792e2014-11-19 12:59:16 +0100133 int led_mode;
Johan Hovold63f44b22014-11-19 12:59:18 +0100134 bool rmii_ref_clk_sel;
135 bool rmii_ref_clk_sel_val;
Andrew Lunn2b2427d2015-12-30 16:28:27 +0100136 u64 stats[ARRAY_SIZE(kszphy_hw_stats)];
Johan Hovolde6a423a2014-11-19 12:59:15 +0100137};
138
139static const struct kszphy_type ksz8021_type = {
140 .led_mode_reg = MII_KSZPHY_CTRL_2,
Johan Hovoldd0e1df92014-12-23 12:59:17 +0100141 .has_broadcast_disable = true,
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100142 .has_nand_tree_disable = true,
Johan Hovold63f44b22014-11-19 12:59:18 +0100143 .has_rmii_ref_clk_sel = true,
Johan Hovolde6a423a2014-11-19 12:59:15 +0100144};
145
146static const struct kszphy_type ksz8041_type = {
147 .led_mode_reg = MII_KSZPHY_CTRL_1,
148};
149
150static const struct kszphy_type ksz8051_type = {
151 .led_mode_reg = MII_KSZPHY_CTRL_2,
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100152 .has_nand_tree_disable = true,
Johan Hovolde6a423a2014-11-19 12:59:15 +0100153};
154
155static const struct kszphy_type ksz8081_type = {
156 .led_mode_reg = MII_KSZPHY_CTRL_2,
Johan Hovold0f959032014-11-19 12:59:17 +0100157 .has_broadcast_disable = true,
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100158 .has_nand_tree_disable = true,
Johan Hovold86dc1342014-11-19 12:59:19 +0100159 .has_rmii_ref_clk_sel = true,
Johan Hovolde6a423a2014-11-19 12:59:15 +0100160};
161
Johan Hovoldc6f95752014-11-19 12:59:22 +0100162static const struct kszphy_type ks8737_type = {
163 .interrupt_level_mask = BIT(14),
164};
165
166static const struct kszphy_type ksz9021_type = {
167 .interrupt_level_mask = BIT(14),
168};
169
Sean Cross954c3962013-08-21 01:46:12 +0000170static int kszphy_extended_write(struct phy_device *phydev,
Florian Fainelli756b5082013-12-17 21:38:11 -0800171 u32 regnum, u16 val)
Sean Cross954c3962013-08-21 01:46:12 +0000172{
173 phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum);
174 return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val);
175}
176
177static int kszphy_extended_read(struct phy_device *phydev,
Florian Fainelli756b5082013-12-17 21:38:11 -0800178 u32 regnum)
Sean Cross954c3962013-08-21 01:46:12 +0000179{
180 phy_write(phydev, MII_KSZPHY_EXTREG, regnum);
181 return phy_read(phydev, MII_KSZPHY_EXTREG_READ);
182}
183
Choi, David51f932c2010-06-28 15:23:41 +0000184static int kszphy_ack_interrupt(struct phy_device *phydev)
185{
186 /* bit[7..0] int status, which is a read and clear register. */
187 int rc;
188
189 rc = phy_read(phydev, MII_KSZPHY_INTCS);
190
191 return (rc < 0) ? rc : 0;
192}
193
Choi, David51f932c2010-06-28 15:23:41 +0000194static int kszphy_config_intr(struct phy_device *phydev)
195{
Johan Hovoldc6f95752014-11-19 12:59:22 +0100196 const struct kszphy_type *type = phydev->drv->driver_data;
Ioana Ciorneic0c99d02020-11-23 17:38:10 +0200197 int temp, err;
Johan Hovoldc6f95752014-11-19 12:59:22 +0100198 u16 mask;
199
200 if (type && type->interrupt_level_mask)
201 mask = type->interrupt_level_mask;
202 else
203 mask = KSZPHY_CTRL_INT_ACTIVE_HIGH;
Choi, David51f932c2010-06-28 15:23:41 +0000204
205 /* set the interrupt pin active low */
206 temp = phy_read(phydev, MII_KSZPHY_CTRL);
Johan Hovold5bb8fc02014-11-11 20:00:08 +0100207 if (temp < 0)
208 return temp;
Johan Hovoldc6f95752014-11-19 12:59:22 +0100209 temp &= ~mask;
Choi, David51f932c2010-06-28 15:23:41 +0000210 phy_write(phydev, MII_KSZPHY_CTRL, temp);
Choi, David51f932c2010-06-28 15:23:41 +0000211
Johan Hovoldc6f95752014-11-19 12:59:22 +0100212 /* enable / disable interrupts */
Ioana Ciorneic0c99d02020-11-23 17:38:10 +0200213 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
214 err = kszphy_ack_interrupt(phydev);
215 if (err)
216 return err;
Choi, David51f932c2010-06-28 15:23:41 +0000217
Ioana Ciorneic0c99d02020-11-23 17:38:10 +0200218 temp = KSZPHY_INTCS_ALL;
219 err = phy_write(phydev, MII_KSZPHY_INTCS, temp);
220 } else {
221 temp = 0;
222 err = phy_write(phydev, MII_KSZPHY_INTCS, temp);
223 if (err)
224 return err;
225
226 err = kszphy_ack_interrupt(phydev);
227 }
228
229 return err;
Choi, David51f932c2010-06-28 15:23:41 +0000230}
David J. Choid0507002010-04-29 06:12:41 +0000231
Ioana Ciornei59ca4e52020-11-23 17:38:09 +0200232static irqreturn_t kszphy_handle_interrupt(struct phy_device *phydev)
233{
234 int irq_status;
235
236 irq_status = phy_read(phydev, MII_KSZPHY_INTCS);
237 if (irq_status < 0) {
238 phy_error(phydev);
239 return IRQ_NONE;
240 }
241
Oleksij Rempelfff4c742020-11-27 13:36:21 +0100242 if (!(irq_status & KSZPHY_INTCS_STATUS))
Ioana Ciornei59ca4e52020-11-23 17:38:09 +0200243 return IRQ_NONE;
244
245 phy_trigger_machine(phydev);
246
247 return IRQ_HANDLED;
248}
249
Johan Hovold63f44b22014-11-19 12:59:18 +0100250static int kszphy_rmii_clk_sel(struct phy_device *phydev, bool val)
251{
252 int ctrl;
253
254 ctrl = phy_read(phydev, MII_KSZPHY_CTRL);
255 if (ctrl < 0)
256 return ctrl;
257
258 if (val)
259 ctrl |= KSZPHY_RMII_REF_CLK_SEL;
260 else
261 ctrl &= ~KSZPHY_RMII_REF_CLK_SEL;
262
263 return phy_write(phydev, MII_KSZPHY_CTRL, ctrl);
264}
265
Johan Hovolde7a792e2014-11-19 12:59:16 +0100266static int kszphy_setup_led(struct phy_device *phydev, u32 reg, int val)
Ben Dooks20d84352014-02-26 11:48:00 +0000267{
Johan Hovold5a167782014-11-11 20:00:14 +0100268 int rc, temp, shift;
Johan Hovold86205462014-11-11 20:00:12 +0100269
Johan Hovold5a167782014-11-11 20:00:14 +0100270 switch (reg) {
271 case MII_KSZPHY_CTRL_1:
272 shift = 14;
273 break;
274 case MII_KSZPHY_CTRL_2:
275 shift = 4;
276 break;
277 default:
278 return -EINVAL;
279 }
280
Ben Dooks20d84352014-02-26 11:48:00 +0000281 temp = phy_read(phydev, reg);
Johan Hovoldb7035862014-11-11 20:00:13 +0100282 if (temp < 0) {
283 rc = temp;
284 goto out;
285 }
Ben Dooks20d84352014-02-26 11:48:00 +0000286
Sergei Shtylyov28bdc492014-03-19 02:58:16 +0300287 temp &= ~(3 << shift);
Ben Dooks20d84352014-02-26 11:48:00 +0000288 temp |= val << shift;
289 rc = phy_write(phydev, reg, temp);
Johan Hovoldb7035862014-11-11 20:00:13 +0100290out:
291 if (rc < 0)
Andrew Lunn72ba48b2016-01-06 20:11:09 +0100292 phydev_err(phydev, "failed to set led mode\n");
Ben Dooks20d84352014-02-26 11:48:00 +0000293
Johan Hovoldb7035862014-11-11 20:00:13 +0100294 return rc;
Ben Dooks20d84352014-02-26 11:48:00 +0000295}
296
Johan Hovoldbde15122014-11-11 20:00:10 +0100297/* Disable PHY address 0 as the broadcast address, so that it can be used as a
298 * unique (non-broadcast) address on a shared bus.
299 */
300static int kszphy_broadcast_disable(struct phy_device *phydev)
301{
302 int ret;
303
304 ret = phy_read(phydev, MII_KSZPHY_OMSO);
305 if (ret < 0)
306 goto out;
307
308 ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
309out:
310 if (ret)
Andrew Lunn72ba48b2016-01-06 20:11:09 +0100311 phydev_err(phydev, "failed to disable broadcast address\n");
Johan Hovoldbde15122014-11-11 20:00:10 +0100312
313 return ret;
314}
315
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100316static int kszphy_nand_tree_disable(struct phy_device *phydev)
317{
318 int ret;
319
320 ret = phy_read(phydev, MII_KSZPHY_OMSO);
321 if (ret < 0)
322 goto out;
323
324 if (!(ret & KSZPHY_OMSO_NAND_TREE_ON))
325 return 0;
326
327 ret = phy_write(phydev, MII_KSZPHY_OMSO,
328 ret & ~KSZPHY_OMSO_NAND_TREE_ON);
329out:
330 if (ret)
Andrew Lunn72ba48b2016-01-06 20:11:09 +0100331 phydev_err(phydev, "failed to disable NAND tree mode\n");
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100332
333 return ret;
334}
335
Leonard Crestez79e498a2017-05-31 13:29:30 +0300336/* Some config bits need to be set again on resume, handle them here. */
337static int kszphy_config_reset(struct phy_device *phydev)
338{
339 struct kszphy_priv *priv = phydev->priv;
340 int ret;
341
342 if (priv->rmii_ref_clk_sel) {
343 ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
344 if (ret) {
345 phydev_err(phydev,
346 "failed to set rmii reference clock\n");
347 return ret;
348 }
349 }
350
351 if (priv->led_mode >= 0)
352 kszphy_setup_led(phydev, priv->type->led_mode_reg, priv->led_mode);
353
354 return 0;
355}
356
David J. Choid0507002010-04-29 06:12:41 +0000357static int kszphy_config_init(struct phy_device *phydev)
358{
Johan Hovolde6a423a2014-11-19 12:59:15 +0100359 struct kszphy_priv *priv = phydev->priv;
360 const struct kszphy_type *type;
David J. Choid0507002010-04-29 06:12:41 +0000361
Johan Hovolde6a423a2014-11-19 12:59:15 +0100362 if (!priv)
363 return 0;
364
365 type = priv->type;
366
Johan Hovold0f959032014-11-19 12:59:17 +0100367 if (type->has_broadcast_disable)
368 kszphy_broadcast_disable(phydev);
369
Sylvain Rochet2b0ba962015-02-13 21:35:33 +0100370 if (type->has_nand_tree_disable)
371 kszphy_nand_tree_disable(phydev);
372
Leonard Crestez79e498a2017-05-31 13:29:30 +0300373 return kszphy_config_reset(phydev);
Ben Dooks20d84352014-02-26 11:48:00 +0000374}
375
Michael Walle4217a642021-02-09 17:38:52 +0100376static int ksz8041_fiber_mode(struct phy_device *phydev)
377{
378 struct device_node *of_node = phydev->mdio.dev.of_node;
379
380 return of_property_read_bool(of_node, "micrel,fiber-mode");
381}
382
Philipp Zabel77501a72016-07-14 16:29:43 +0200383static int ksz8041_config_init(struct phy_device *phydev)
384{
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100385 __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
386
Philipp Zabel77501a72016-07-14 16:29:43 +0200387 /* Limit supported and advertised modes in fiber mode */
Michael Walle4217a642021-02-09 17:38:52 +0100388 if (ksz8041_fiber_mode(phydev)) {
Philipp Zabel77501a72016-07-14 16:29:43 +0200389 phydev->dev_flags |= MICREL_PHY_FXEN;
Andrew Lunn3c1bcc82018-11-10 23:43:33 +0100390 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, mask);
391 linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, mask);
392
393 linkmode_and(phydev->supported, phydev->supported, mask);
394 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
395 phydev->supported);
396 linkmode_and(phydev->advertising, phydev->advertising, mask);
397 linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
398 phydev->advertising);
Philipp Zabel77501a72016-07-14 16:29:43 +0200399 phydev->autoneg = AUTONEG_DISABLE;
400 }
401
402 return kszphy_config_init(phydev);
403}
404
405static int ksz8041_config_aneg(struct phy_device *phydev)
406{
407 /* Skip auto-negotiation in fiber mode */
408 if (phydev->dev_flags & MICREL_PHY_FXEN) {
409 phydev->speed = SPEED_100;
410 return 0;
411 }
412
413 return genphy_config_aneg(phydev);
414}
415
Marek Vasut8b955992019-10-16 15:35:06 +0200416static int ksz8051_ksz8795_match_phy_device(struct phy_device *phydev,
Steve Bennetta5e63c72021-07-31 08:57:50 +1000417 const bool ksz_8051)
Marek Vasut8b955992019-10-16 15:35:06 +0200418{
419 int ret;
420
Steve Bennetta5e63c72021-07-31 08:57:50 +1000421 if ((phydev->phy_id & MICREL_PHY_ID_MASK) != PHY_ID_KSZ8051)
Marek Vasut8b955992019-10-16 15:35:06 +0200422 return 0;
423
424 ret = phy_read(phydev, MII_BMSR);
425 if (ret < 0)
426 return ret;
427
428 /* KSZ8051 PHY and KSZ8794/KSZ8795/KSZ8765 switch share the same
429 * exact PHY ID. However, they can be told apart by the extended
430 * capability registers presence. The KSZ8051 PHY has them while
431 * the switch does not.
432 */
433 ret &= BMSR_ERCAP;
Steve Bennetta5e63c72021-07-31 08:57:50 +1000434 if (ksz_8051)
Marek Vasut8b955992019-10-16 15:35:06 +0200435 return ret;
436 else
437 return !ret;
438}
439
440static int ksz8051_match_phy_device(struct phy_device *phydev)
441{
Steve Bennetta5e63c72021-07-31 08:57:50 +1000442 return ksz8051_ksz8795_match_phy_device(phydev, true);
Marek Vasut8b955992019-10-16 15:35:06 +0200443}
444
Antoine Tenart7a1d8392019-04-26 18:41:23 +0200445static int ksz8081_config_init(struct phy_device *phydev)
446{
447 /* KSZPHY_OMSO_FACTORY_TEST is set at de-assertion of the reset line
448 * based on the RXER (KSZ8081RNA/RND) or TXC (KSZ8081MNX/RNB) pin. If a
449 * pull-down is missing, the factory test mode should be cleared by
450 * manually writing a 0.
451 */
452 phy_clear_bits(phydev, MII_KSZPHY_OMSO, KSZPHY_OMSO_FACTORY_TEST);
453
454 return kszphy_config_init(phydev);
455}
456
Oleksij Rempelf873f112021-06-14 06:31:22 +0200457static int ksz8081_config_mdix(struct phy_device *phydev, u8 ctrl)
458{
459 u16 val;
460
461 switch (ctrl) {
462 case ETH_TP_MDI:
463 val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX;
464 break;
465 case ETH_TP_MDI_X:
466 val = KSZ8081_CTRL2_DISABLE_AUTO_MDIX |
467 KSZ8081_CTRL2_MDI_MDI_X_SELECT;
468 break;
469 case ETH_TP_MDI_AUTO:
470 val = 0;
471 break;
472 default:
473 return 0;
474 }
475
476 return phy_modify(phydev, MII_KSZPHY_CTRL_2,
477 KSZ8081_CTRL2_HP_MDIX |
478 KSZ8081_CTRL2_MDI_MDI_X_SELECT |
479 KSZ8081_CTRL2_DISABLE_AUTO_MDIX,
480 KSZ8081_CTRL2_HP_MDIX | val);
481}
482
483static int ksz8081_config_aneg(struct phy_device *phydev)
484{
485 int ret;
486
487 ret = genphy_config_aneg(phydev);
488 if (ret)
489 return ret;
490
491 /* The MDI-X configuration is automatically changed by the PHY after
492 * switching from autoneg off to on. So, take MDI-X configuration under
493 * own control and set it after autoneg configuration was done.
494 */
495 return ksz8081_config_mdix(phydev, phydev->mdix_ctrl);
496}
497
498static int ksz8081_mdix_update(struct phy_device *phydev)
499{
500 int ret;
501
502 ret = phy_read(phydev, MII_KSZPHY_CTRL_2);
503 if (ret < 0)
504 return ret;
505
506 if (ret & KSZ8081_CTRL2_DISABLE_AUTO_MDIX) {
507 if (ret & KSZ8081_CTRL2_MDI_MDI_X_SELECT)
508 phydev->mdix_ctrl = ETH_TP_MDI_X;
509 else
510 phydev->mdix_ctrl = ETH_TP_MDI;
511 } else {
512 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
513 }
514
515 ret = phy_read(phydev, MII_KSZPHY_CTRL_1);
516 if (ret < 0)
517 return ret;
518
519 if (ret & KSZ8081_CTRL1_MDIX_STAT)
520 phydev->mdix = ETH_TP_MDI;
521 else
522 phydev->mdix = ETH_TP_MDI_X;
523
524 return 0;
525}
526
527static int ksz8081_read_status(struct phy_device *phydev)
528{
529 int ret;
530
531 ret = ksz8081_mdix_update(phydev);
532 if (ret < 0)
533 return ret;
534
535 return genphy_read_status(phydev);
536}
537
Rajasingh Thavamani232ba3a2019-02-27 17:43:19 +0530538static int ksz8061_config_init(struct phy_device *phydev)
539{
540 int ret;
541
542 ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A);
543 if (ret)
544 return ret;
545
546 return kszphy_config_init(phydev);
547}
548
Marek Vasut8b955992019-10-16 15:35:06 +0200549static int ksz8795_match_phy_device(struct phy_device *phydev)
550{
Steve Bennetta5e63c72021-07-31 08:57:50 +1000551 return ksz8051_ksz8795_match_phy_device(phydev, false);
Marek Vasut8b955992019-10-16 15:35:06 +0200552}
553
Sean Cross954c3962013-08-21 01:46:12 +0000554static int ksz9021_load_values_from_of(struct phy_device *phydev,
Jaeden Amero3c9a9f72015-06-05 18:00:24 -0500555 const struct device_node *of_node,
556 u16 reg,
557 const char *field1, const char *field2,
558 const char *field3, const char *field4)
Sean Cross954c3962013-08-21 01:46:12 +0000559{
560 int val1 = -1;
561 int val2 = -2;
562 int val3 = -3;
563 int val4 = -4;
564 int newval;
565 int matches = 0;
566
567 if (!of_property_read_u32(of_node, field1, &val1))
568 matches++;
569
570 if (!of_property_read_u32(of_node, field2, &val2))
571 matches++;
572
573 if (!of_property_read_u32(of_node, field3, &val3))
574 matches++;
575
576 if (!of_property_read_u32(of_node, field4, &val4))
577 matches++;
578
579 if (!matches)
580 return 0;
581
582 if (matches < 4)
583 newval = kszphy_extended_read(phydev, reg);
584 else
585 newval = 0;
586
587 if (val1 != -1)
588 newval = ((newval & 0xfff0) | ((val1 / PS_TO_REG) & 0xf) << 0);
589
Hubert Chaumette6a119742014-04-22 15:01:04 +0200590 if (val2 != -2)
Sean Cross954c3962013-08-21 01:46:12 +0000591 newval = ((newval & 0xff0f) | ((val2 / PS_TO_REG) & 0xf) << 4);
592
Hubert Chaumette6a119742014-04-22 15:01:04 +0200593 if (val3 != -3)
Sean Cross954c3962013-08-21 01:46:12 +0000594 newval = ((newval & 0xf0ff) | ((val3 / PS_TO_REG) & 0xf) << 8);
595
Hubert Chaumette6a119742014-04-22 15:01:04 +0200596 if (val4 != -4)
Sean Cross954c3962013-08-21 01:46:12 +0000597 newval = ((newval & 0x0fff) | ((val4 / PS_TO_REG) & 0xf) << 12);
598
599 return kszphy_extended_write(phydev, reg, newval);
600}
601
602static int ksz9021_config_init(struct phy_device *phydev)
603{
Colin Ian Kingce4f8af2021-06-13 14:27:40 +0100604 const struct device_node *of_node;
Andrew Lunn651df212015-12-09 19:56:31 +0100605 const struct device *dev_walker;
Sean Cross954c3962013-08-21 01:46:12 +0000606
Andrew Lunn651df212015-12-09 19:56:31 +0100607 /* The Micrel driver has a deprecated option to place phy OF
608 * properties in the MAC node. Walk up the tree of devices to
609 * find a device with an OF node.
610 */
Andrew Lunne5a03bf2016-01-06 20:11:16 +0100611 dev_walker = &phydev->mdio.dev;
Andrew Lunn651df212015-12-09 19:56:31 +0100612 do {
613 of_node = dev_walker->of_node;
614 dev_walker = dev_walker->parent;
615
616 } while (!of_node && dev_walker);
Sean Cross954c3962013-08-21 01:46:12 +0000617
618 if (of_node) {
619 ksz9021_load_values_from_of(phydev, of_node,
620 MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
621 "txen-skew-ps", "txc-skew-ps",
622 "rxdv-skew-ps", "rxc-skew-ps");
623 ksz9021_load_values_from_of(phydev, of_node,
624 MII_KSZPHY_RX_DATA_PAD_SKEW,
625 "rxd0-skew-ps", "rxd1-skew-ps",
626 "rxd2-skew-ps", "rxd3-skew-ps");
627 ksz9021_load_values_from_of(phydev, of_node,
628 MII_KSZPHY_TX_DATA_PAD_SKEW,
629 "txd0-skew-ps", "txd1-skew-ps",
630 "txd2-skew-ps", "txd3-skew-ps");
631 }
632 return 0;
633}
634
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200635#define KSZ9031_PS_TO_REG 60
636
637/* Extended registers */
Jaeden Amero6270e1a2015-06-05 18:00:26 -0500638/* MMD Address 0x0 */
639#define MII_KSZ9031RN_FLP_BURST_TX_LO 3
640#define MII_KSZ9031RN_FLP_BURST_TX_HI 4
641
Jaeden Ameroae6c97b2015-06-05 18:00:25 -0500642/* MMD Address 0x2 */
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200643#define MII_KSZ9031RN_CONTROL_PAD_SKEW 4
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200644#define MII_KSZ9031RN_RX_CTL_M GENMASK(7, 4)
645#define MII_KSZ9031RN_TX_CTL_M GENMASK(3, 0)
646
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200647#define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200648#define MII_KSZ9031RN_RXD3 GENMASK(15, 12)
649#define MII_KSZ9031RN_RXD2 GENMASK(11, 8)
650#define MII_KSZ9031RN_RXD1 GENMASK(7, 4)
651#define MII_KSZ9031RN_RXD0 GENMASK(3, 0)
652
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200653#define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200654#define MII_KSZ9031RN_TXD3 GENMASK(15, 12)
655#define MII_KSZ9031RN_TXD2 GENMASK(11, 8)
656#define MII_KSZ9031RN_TXD1 GENMASK(7, 4)
657#define MII_KSZ9031RN_TXD0 GENMASK(3, 0)
658
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200659#define MII_KSZ9031RN_CLK_PAD_SKEW 8
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200660#define MII_KSZ9031RN_GTX_CLK GENMASK(9, 5)
661#define MII_KSZ9031RN_RX_CLK GENMASK(4, 0)
662
663/* KSZ9031 has internal RGMII_IDRX = 1.2ns and RGMII_IDTX = 0ns. To
664 * provide different RGMII options we need to configure delay offset
665 * for each pad relative to build in delay.
666 */
667/* keep rx as "No delay adjustment" and set rx_clk to +0.60ns to get delays of
668 * 1.80ns
669 */
670#define RX_ID 0x7
671#define RX_CLK_ID 0x19
672
673/* set rx to +0.30ns and rx_clk to -0.90ns to compensate the
674 * internal 1.2ns delay.
675 */
676#define RX_ND 0xc
677#define RX_CLK_ND 0x0
678
679/* set tx to -0.42ns and tx_clk to +0.96ns to get 1.38ns delay */
680#define TX_ID 0x0
681#define TX_CLK_ID 0x1f
682
683/* set tx and tx_clk to "No delay adjustment" to keep 0ns
684 * dealy
685 */
686#define TX_ND 0x7
687#define TX_CLK_ND 0xf
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200688
Mike Looijmansaf70c1f2016-10-04 07:52:04 +0200689/* MMD Address 0x1C */
690#define MII_KSZ9031RN_EDPD 0x23
691#define MII_KSZ9031RN_EDPD_ENABLE BIT(0)
692
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200693static int ksz9031_of_load_skew_values(struct phy_device *phydev,
Jaeden Amero3c9a9f72015-06-05 18:00:24 -0500694 const struct device_node *of_node,
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200695 u16 reg, size_t field_sz,
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200696 const char *field[], u8 numfields,
697 bool *update)
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200698{
699 int val[4] = {-1, -2, -3, -4};
700 int matches = 0;
701 u16 mask;
702 u16 maxval;
703 u16 newval;
704 int i;
705
706 for (i = 0; i < numfields; i++)
707 if (!of_property_read_u32(of_node, field[i], val + i))
708 matches++;
709
710 if (!matches)
711 return 0;
712
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200713 *update |= true;
714
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200715 if (matches < numfields)
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100716 newval = phy_read_mmd(phydev, 2, reg);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200717 else
718 newval = 0;
719
720 maxval = (field_sz == 4) ? 0xf : 0x1f;
721 for (i = 0; i < numfields; i++)
722 if (val[i] != -(i + 1)) {
723 mask = 0xffff;
724 mask ^= maxval << (field_sz * i);
725 newval = (newval & mask) |
726 (((val[i] / KSZ9031_PS_TO_REG) & maxval)
727 << (field_sz * i));
728 }
729
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100730 return phy_write_mmd(phydev, 2, reg, newval);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200731}
732
Max Uvarova0da4562017-11-30 13:08:29 +0300733/* Center KSZ9031RNX FLP timing at 16ms. */
Jaeden Amero6270e1a2015-06-05 18:00:26 -0500734static int ksz9031_center_flp_timing(struct phy_device *phydev)
735{
736 int result;
737
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100738 result = phy_write_mmd(phydev, 0, MII_KSZ9031RN_FLP_BURST_TX_HI,
739 0x0006);
Max Uvarova0da4562017-11-30 13:08:29 +0300740 if (result)
741 return result;
742
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100743 result = phy_write_mmd(phydev, 0, MII_KSZ9031RN_FLP_BURST_TX_LO,
744 0x1A80);
Jaeden Amero6270e1a2015-06-05 18:00:26 -0500745 if (result)
746 return result;
747
748 return genphy_restart_aneg(phydev);
749}
750
Mike Looijmansaf70c1f2016-10-04 07:52:04 +0200751/* Enable energy-detect power-down mode */
752static int ksz9031_enable_edpd(struct phy_device *phydev)
753{
754 int reg;
755
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100756 reg = phy_read_mmd(phydev, 0x1C, MII_KSZ9031RN_EDPD);
Mike Looijmansaf70c1f2016-10-04 07:52:04 +0200757 if (reg < 0)
758 return reg;
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100759 return phy_write_mmd(phydev, 0x1C, MII_KSZ9031RN_EDPD,
760 reg | MII_KSZ9031RN_EDPD_ENABLE);
Mike Looijmansaf70c1f2016-10-04 07:52:04 +0200761}
762
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200763static int ksz9031_config_rgmii_delay(struct phy_device *phydev)
764{
765 u16 rx, tx, rx_clk, tx_clk;
766 int ret;
767
768 switch (phydev->interface) {
769 case PHY_INTERFACE_MODE_RGMII:
770 tx = TX_ND;
771 tx_clk = TX_CLK_ND;
772 rx = RX_ND;
773 rx_clk = RX_CLK_ND;
774 break;
775 case PHY_INTERFACE_MODE_RGMII_ID:
776 tx = TX_ID;
777 tx_clk = TX_CLK_ID;
778 rx = RX_ID;
779 rx_clk = RX_CLK_ID;
780 break;
781 case PHY_INTERFACE_MODE_RGMII_RXID:
782 tx = TX_ND;
783 tx_clk = TX_CLK_ND;
784 rx = RX_ID;
785 rx_clk = RX_CLK_ID;
786 break;
787 case PHY_INTERFACE_MODE_RGMII_TXID:
788 tx = TX_ID;
789 tx_clk = TX_CLK_ID;
790 rx = RX_ND;
791 rx_clk = RX_CLK_ND;
792 break;
793 default:
794 return 0;
795 }
796
797 ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_CONTROL_PAD_SKEW,
798 FIELD_PREP(MII_KSZ9031RN_RX_CTL_M, rx) |
799 FIELD_PREP(MII_KSZ9031RN_TX_CTL_M, tx));
800 if (ret < 0)
801 return ret;
802
803 ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_RX_DATA_PAD_SKEW,
804 FIELD_PREP(MII_KSZ9031RN_RXD3, rx) |
805 FIELD_PREP(MII_KSZ9031RN_RXD2, rx) |
806 FIELD_PREP(MII_KSZ9031RN_RXD1, rx) |
807 FIELD_PREP(MII_KSZ9031RN_RXD0, rx));
808 if (ret < 0)
809 return ret;
810
811 ret = phy_write_mmd(phydev, 2, MII_KSZ9031RN_TX_DATA_PAD_SKEW,
812 FIELD_PREP(MII_KSZ9031RN_TXD3, tx) |
813 FIELD_PREP(MII_KSZ9031RN_TXD2, tx) |
814 FIELD_PREP(MII_KSZ9031RN_TXD1, tx) |
815 FIELD_PREP(MII_KSZ9031RN_TXD0, tx));
816 if (ret < 0)
817 return ret;
818
819 return phy_write_mmd(phydev, 2, MII_KSZ9031RN_CLK_PAD_SKEW,
820 FIELD_PREP(MII_KSZ9031RN_GTX_CLK, tx_clk) |
821 FIELD_PREP(MII_KSZ9031RN_RX_CLK, rx_clk));
822}
823
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200824static int ksz9031_config_init(struct phy_device *phydev)
825{
Colin Ian Kingce4f8af2021-06-13 14:27:40 +0100826 const struct device_node *of_node;
Jaeden Amero3c9a9f72015-06-05 18:00:24 -0500827 static const char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
828 static const char *rx_data_skews[4] = {
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200829 "rxd0-skew-ps", "rxd1-skew-ps",
830 "rxd2-skew-ps", "rxd3-skew-ps"
831 };
Jaeden Amero3c9a9f72015-06-05 18:00:24 -0500832 static const char *tx_data_skews[4] = {
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200833 "txd0-skew-ps", "txd1-skew-ps",
834 "txd2-skew-ps", "txd3-skew-ps"
835 };
Jaeden Amero3c9a9f72015-06-05 18:00:24 -0500836 static const char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
Roosen Henrib4c19f72016-01-07 09:31:15 +0100837 const struct device *dev_walker;
Mike Looijmansaf70c1f2016-10-04 07:52:04 +0200838 int result;
839
840 result = ksz9031_enable_edpd(phydev);
841 if (result < 0)
842 return result;
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200843
Roosen Henrib4c19f72016-01-07 09:31:15 +0100844 /* The Micrel driver has a deprecated option to place phy OF
845 * properties in the MAC node. Walk up the tree of devices to
846 * find a device with an OF node.
847 */
David S. Miller9d367ed2016-01-11 23:55:43 -0500848 dev_walker = &phydev->mdio.dev;
Roosen Henrib4c19f72016-01-07 09:31:15 +0100849 do {
850 of_node = dev_walker->of_node;
851 dev_walker = dev_walker->parent;
852 } while (!of_node && dev_walker);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200853
854 if (of_node) {
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200855 bool update = false;
856
857 if (phy_interface_is_rgmii(phydev)) {
858 result = ksz9031_config_rgmii_delay(phydev);
859 if (result < 0)
860 return result;
861 }
862
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200863 ksz9031_of_load_skew_values(phydev, of_node,
864 MII_KSZ9031RN_CLK_PAD_SKEW, 5,
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200865 clk_skews, 2, &update);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200866
867 ksz9031_of_load_skew_values(phydev, of_node,
868 MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200869 control_skews, 2, &update);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200870
871 ksz9031_of_load_skew_values(phydev, of_node,
872 MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200873 rx_data_skews, 4, &update);
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200874
875 ksz9031_of_load_skew_values(phydev, of_node,
876 MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200877 tx_data_skews, 4, &update);
878
Matthias Schiffer67ca5152021-10-12 12:34:02 +0200879 if (update && !phy_interface_is_rgmii(phydev))
Oleksij Rempelbcf34402020-04-22 09:21:37 +0200880 phydev_warn(phydev,
Matthias Schiffer67ca5152021-10-12 12:34:02 +0200881 "*-skew-ps values should be used only with RGMII PHY modes\n");
Markus Niebele1b505a2018-05-15 10:18:56 +0200882
883 /* Silicon Errata Sheet (DS80000691D or DS80000692D):
884 * When the device links in the 1000BASE-T slave mode only,
885 * the optional 125MHz reference output clock (CLK125_NDO)
886 * has wide duty cycle variation.
887 *
888 * The optional CLK125_NDO clock does not meet the RGMII
889 * 45/55 percent (min/max) duty cycle requirement and therefore
890 * cannot be used directly by the MAC side for clocking
891 * applications that have setup/hold time requirements on
892 * rising and falling clock edges.
893 *
894 * Workaround:
895 * Force the phy to be the master to receive a stable clock
896 * which meets the duty cycle requirement.
897 */
898 if (of_property_read_bool(of_node, "micrel,force-master")) {
899 result = phy_read(phydev, MII_CTRL1000);
900 if (result < 0)
901 goto err_force_master;
902
903 /* enable master mode, config & prefer master */
904 result |= CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER;
905 result = phy_write(phydev, MII_CTRL1000, result);
906 if (result < 0)
907 goto err_force_master;
908 }
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200909 }
Jaeden Amero6270e1a2015-06-05 18:00:26 -0500910
911 return ksz9031_center_flp_timing(phydev);
Markus Niebele1b505a2018-05-15 10:18:56 +0200912
913err_force_master:
914 phydev_err(phydev, "failed to force the phy to master mode\n");
915 return result;
Hubert Chaumette6e4b8272014-05-06 09:40:17 +0200916}
917
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -0400918#define KSZ9131_SKEW_5BIT_MAX 2400
919#define KSZ9131_SKEW_4BIT_MAX 800
920#define KSZ9131_OFFSET 700
921#define KSZ9131_STEP 100
922
923static int ksz9131_of_load_skew_values(struct phy_device *phydev,
924 struct device_node *of_node,
925 u16 reg, size_t field_sz,
926 char *field[], u8 numfields)
927{
928 int val[4] = {-(1 + KSZ9131_OFFSET), -(2 + KSZ9131_OFFSET),
929 -(3 + KSZ9131_OFFSET), -(4 + KSZ9131_OFFSET)};
930 int skewval, skewmax = 0;
931 int matches = 0;
932 u16 maxval;
933 u16 newval;
934 u16 mask;
935 int i;
936
937 /* psec properties in dts should mean x pico seconds */
938 if (field_sz == 5)
939 skewmax = KSZ9131_SKEW_5BIT_MAX;
940 else
941 skewmax = KSZ9131_SKEW_4BIT_MAX;
942
943 for (i = 0; i < numfields; i++)
944 if (!of_property_read_s32(of_node, field[i], &skewval)) {
945 if (skewval < -KSZ9131_OFFSET)
946 skewval = -KSZ9131_OFFSET;
947 else if (skewval > skewmax)
948 skewval = skewmax;
949
950 val[i] = skewval + KSZ9131_OFFSET;
951 matches++;
952 }
953
954 if (!matches)
955 return 0;
956
957 if (matches < numfields)
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100958 newval = phy_read_mmd(phydev, 2, reg);
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -0400959 else
960 newval = 0;
961
962 maxval = (field_sz == 4) ? 0xf : 0x1f;
963 for (i = 0; i < numfields; i++)
964 if (val[i] != -(i + 1 + KSZ9131_OFFSET)) {
965 mask = 0xffff;
966 mask ^= maxval << (field_sz * i);
967 newval = (newval & mask) |
968 (((val[i] / KSZ9131_STEP) & maxval)
969 << (field_sz * i));
970 }
971
Heiner Kallweit9b420ef2019-01-16 21:52:22 +0100972 return phy_write_mmd(phydev, 2, reg, newval);
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -0400973}
974
Philippe Schenkerbd734a72020-03-25 18:34:24 +0100975#define KSZ9131RN_MMD_COMMON_CTRL_REG 2
976#define KSZ9131RN_RXC_DLL_CTRL 76
977#define KSZ9131RN_TXC_DLL_CTRL 77
978#define KSZ9131RN_DLL_CTRL_BYPASS BIT_MASK(12)
979#define KSZ9131RN_DLL_ENABLE_DELAY 0
980#define KSZ9131RN_DLL_DISABLE_DELAY BIT(12)
981
982static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
983{
984 u16 rxcdll_val, txcdll_val;
985 int ret;
986
987 switch (phydev->interface) {
988 case PHY_INTERFACE_MODE_RGMII:
989 rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
990 txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
991 break;
992 case PHY_INTERFACE_MODE_RGMII_ID:
993 rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
994 txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
995 break;
996 case PHY_INTERFACE_MODE_RGMII_RXID:
997 rxcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
998 txcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
999 break;
1000 case PHY_INTERFACE_MODE_RGMII_TXID:
1001 rxcdll_val = KSZ9131RN_DLL_DISABLE_DELAY;
1002 txcdll_val = KSZ9131RN_DLL_ENABLE_DELAY;
1003 break;
1004 default:
1005 return 0;
1006 }
1007
1008 ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
1009 KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
1010 rxcdll_val);
1011 if (ret < 0)
1012 return ret;
1013
1014 return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
1015 KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
1016 txcdll_val);
1017}
1018
Francesco Dolcini0316c7e2021-10-07 18:45:35 +02001019/* Silicon Errata DS80000693B
1020 *
1021 * When LEDs are configured in Individual Mode, LED1 is ON in a no-link
1022 * condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
1023 * according to the datasheet (off if there is no link).
1024 */
1025static int ksz9131_led_errata(struct phy_device *phydev)
1026{
1027 int reg;
1028
1029 reg = phy_read_mmd(phydev, 2, 0);
1030 if (reg < 0)
1031 return reg;
1032
1033 if (!(reg & BIT(4)))
1034 return 0;
1035
1036 return phy_set_bits(phydev, 0x1e, BIT(9));
1037}
1038
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001039static int ksz9131_config_init(struct phy_device *phydev)
1040{
Colin Ian Kingce4f8af2021-06-13 14:27:40 +01001041 struct device_node *of_node;
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001042 char *clk_skews[2] = {"rxc-skew-psec", "txc-skew-psec"};
1043 char *rx_data_skews[4] = {
1044 "rxd0-skew-psec", "rxd1-skew-psec",
1045 "rxd2-skew-psec", "rxd3-skew-psec"
1046 };
1047 char *tx_data_skews[4] = {
1048 "txd0-skew-psec", "txd1-skew-psec",
1049 "txd2-skew-psec", "txd3-skew-psec"
1050 };
1051 char *control_skews[2] = {"txen-skew-psec", "rxdv-skew-psec"};
1052 const struct device *dev_walker;
1053 int ret;
1054
1055 dev_walker = &phydev->mdio.dev;
1056 do {
1057 of_node = dev_walker->of_node;
1058 dev_walker = dev_walker->parent;
1059 } while (!of_node && dev_walker);
1060
1061 if (!of_node)
1062 return 0;
1063
Philippe Schenkerbd734a72020-03-25 18:34:24 +01001064 if (phy_interface_is_rgmii(phydev)) {
1065 ret = ksz9131_config_rgmii_delay(phydev);
1066 if (ret < 0)
1067 return ret;
1068 }
1069
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001070 ret = ksz9131_of_load_skew_values(phydev, of_node,
1071 MII_KSZ9031RN_CLK_PAD_SKEW, 5,
1072 clk_skews, 2);
1073 if (ret < 0)
1074 return ret;
1075
1076 ret = ksz9131_of_load_skew_values(phydev, of_node,
1077 MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
1078 control_skews, 2);
1079 if (ret < 0)
1080 return ret;
1081
1082 ret = ksz9131_of_load_skew_values(phydev, of_node,
1083 MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
1084 rx_data_skews, 4);
1085 if (ret < 0)
1086 return ret;
1087
1088 ret = ksz9131_of_load_skew_values(phydev, of_node,
1089 MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
1090 tx_data_skews, 4);
1091 if (ret < 0)
1092 return ret;
1093
Francesco Dolcini0316c7e2021-10-07 18:45:35 +02001094 ret = ksz9131_led_errata(phydev);
1095 if (ret < 0)
1096 return ret;
1097
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001098 return 0;
1099}
1100
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001101#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
Johan Hovold00aee092014-11-11 20:00:09 +01001102#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX BIT(6)
1103#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED BIT(4)
Jingoo Han32d73b12013-08-06 17:29:35 +09001104static int ksz8873mll_read_status(struct phy_device *phydev)
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001105{
1106 int regval;
1107
1108 /* dummy read */
1109 regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
1110
1111 regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
1112
1113 if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
1114 phydev->duplex = DUPLEX_HALF;
1115 else
1116 phydev->duplex = DUPLEX_FULL;
1117
1118 if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
1119 phydev->speed = SPEED_10;
1120 else
1121 phydev->speed = SPEED_100;
1122
1123 phydev->link = 1;
1124 phydev->pause = phydev->asym_pause = 0;
1125
1126 return 0;
1127}
1128
Antoine Tenart3aed3e22019-04-16 12:10:20 +02001129static int ksz9031_get_features(struct phy_device *phydev)
1130{
1131 int ret;
1132
1133 ret = genphy_read_abilities(phydev);
1134 if (ret < 0)
1135 return ret;
1136
1137 /* Silicon Errata Sheet (DS80000691D or DS80000692D):
1138 * Whenever the device's Asymmetric Pause capability is set to 1,
1139 * link-up may fail after a link-up to link-down transition.
1140 *
Hans Andersson407d8092019-09-26 09:54:37 +02001141 * The Errata Sheet is for ksz9031, but ksz9021 has the same issue
1142 *
Antoine Tenart3aed3e22019-04-16 12:10:20 +02001143 * Workaround:
1144 * Do not enable the Asymmetric Pause capability bit.
1145 */
1146 linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
1147
1148 /* We force setting the Pause capability as the core will force the
1149 * Asymmetric Pause capability to 1 otherwise.
1150 */
1151 linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
1152
1153 return 0;
1154}
1155
Nathan Sullivand2fd7192015-10-21 14:17:04 -05001156static int ksz9031_read_status(struct phy_device *phydev)
1157{
1158 int err;
1159 int regval;
1160
1161 err = genphy_read_status(phydev);
1162 if (err)
1163 return err;
1164
1165 /* Make sure the PHY is not broken. Read idle error count,
1166 * and reset the PHY if it is maxed out.
1167 */
1168 regval = phy_read(phydev, MII_STAT1000);
1169 if ((regval & 0xFF) == 0xFF) {
1170 phy_init_hw(phydev);
1171 phydev->link = 0;
Zach Brownb8662032017-06-20 12:48:11 -05001172 if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev))
1173 phydev->drv->config_intr(phydev);
Grygorii Strashkoc1a8d0a2017-12-20 18:45:10 -06001174 return genphy_config_aneg(phydev);
Nathan Sullivand2fd7192015-10-21 14:17:04 -05001175 }
1176
1177 return 0;
1178}
1179
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001180static int ksz8873mll_config_aneg(struct phy_device *phydev)
1181{
1182 return 0;
1183}
1184
Oleksij Rempel52939392021-06-14 06:31:21 +02001185static int ksz886x_config_mdix(struct phy_device *phydev, u8 ctrl)
1186{
1187 u16 val;
1188
1189 switch (ctrl) {
1190 case ETH_TP_MDI:
1191 val = KSZ886X_BMCR_DISABLE_AUTO_MDIX;
1192 break;
1193 case ETH_TP_MDI_X:
1194 /* Note: The naming of the bit KSZ886X_BMCR_FORCE_MDI is bit
1195 * counter intuitive, the "-X" in "1 = Force MDI" in the data
1196 * sheet seems to be missing:
1197 * 1 = Force MDI (sic!) (transmit on RX+/RX- pins)
1198 * 0 = Normal operation (transmit on TX+/TX- pins)
1199 */
1200 val = KSZ886X_BMCR_DISABLE_AUTO_MDIX | KSZ886X_BMCR_FORCE_MDI;
1201 break;
1202 case ETH_TP_MDI_AUTO:
1203 val = 0;
1204 break;
1205 default:
1206 return 0;
1207 }
1208
1209 return phy_modify(phydev, MII_BMCR,
1210 KSZ886X_BMCR_HP_MDIX | KSZ886X_BMCR_FORCE_MDI |
1211 KSZ886X_BMCR_DISABLE_AUTO_MDIX,
1212 KSZ886X_BMCR_HP_MDIX | val);
1213}
1214
1215static int ksz886x_config_aneg(struct phy_device *phydev)
1216{
1217 int ret;
1218
1219 ret = genphy_config_aneg(phydev);
1220 if (ret)
1221 return ret;
1222
1223 /* The MDI-X configuration is automatically changed by the PHY after
1224 * switching from autoneg off to on. So, take MDI-X configuration under
1225 * own control and set it after autoneg configuration was done.
1226 */
1227 return ksz886x_config_mdix(phydev, phydev->mdix_ctrl);
1228}
1229
1230static int ksz886x_mdix_update(struct phy_device *phydev)
1231{
1232 int ret;
1233
1234 ret = phy_read(phydev, MII_BMCR);
1235 if (ret < 0)
1236 return ret;
1237
1238 if (ret & KSZ886X_BMCR_DISABLE_AUTO_MDIX) {
1239 if (ret & KSZ886X_BMCR_FORCE_MDI)
1240 phydev->mdix_ctrl = ETH_TP_MDI_X;
1241 else
1242 phydev->mdix_ctrl = ETH_TP_MDI;
1243 } else {
1244 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
1245 }
1246
1247 ret = phy_read(phydev, MII_KSZPHY_CTRL);
1248 if (ret < 0)
1249 return ret;
1250
1251 /* Same reverse logic as KSZ886X_BMCR_FORCE_MDI */
1252 if (ret & KSZ886X_CTRL_MDIX_STAT)
1253 phydev->mdix = ETH_TP_MDI_X;
1254 else
1255 phydev->mdix = ETH_TP_MDI;
1256
1257 return 0;
1258}
1259
1260static int ksz886x_read_status(struct phy_device *phydev)
1261{
1262 int ret;
1263
1264 ret = ksz886x_mdix_update(phydev);
1265 if (ret < 0)
1266 return ret;
1267
1268 return genphy_read_status(phydev);
1269}
1270
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001271static int kszphy_get_sset_count(struct phy_device *phydev)
1272{
1273 return ARRAY_SIZE(kszphy_hw_stats);
1274}
1275
1276static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
1277{
1278 int i;
1279
1280 for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
Florian Fainelli55f53562018-03-02 15:08:38 -08001281 strlcpy(data + i * ETH_GSTRING_LEN,
1282 kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001283 }
1284}
1285
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001286static u64 kszphy_get_stat(struct phy_device *phydev, int i)
1287{
1288 struct kszphy_hw_stat stat = kszphy_hw_stats[i];
1289 struct kszphy_priv *priv = phydev->priv;
Andrew Lunn321b4d42016-02-20 00:35:29 +01001290 int val;
1291 u64 ret;
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001292
1293 val = phy_read(phydev, stat.reg);
1294 if (val < 0) {
Jisheng Zhang6c3442f2018-04-27 16:18:58 +08001295 ret = U64_MAX;
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001296 } else {
1297 val = val & ((1 << stat.bits) - 1);
1298 priv->stats[i] += val;
Andrew Lunn321b4d42016-02-20 00:35:29 +01001299 ret = priv->stats[i];
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001300 }
1301
Andrew Lunn321b4d42016-02-20 00:35:29 +01001302 return ret;
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001303}
1304
1305static void kszphy_get_stats(struct phy_device *phydev,
1306 struct ethtool_stats *stats, u64 *data)
1307{
1308 int i;
1309
1310 for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++)
1311 data[i] = kszphy_get_stat(phydev, i);
1312}
1313
Wenyou Yang836384d2016-08-05 14:35:41 +08001314static int kszphy_suspend(struct phy_device *phydev)
1315{
1316 /* Disable PHY Interrupts */
1317 if (phy_interrupt_is_valid(phydev)) {
1318 phydev->interrupts = PHY_INTERRUPT_DISABLED;
1319 if (phydev->drv->config_intr)
1320 phydev->drv->config_intr(phydev);
1321 }
1322
1323 return genphy_suspend(phydev);
1324}
1325
Alexandre Bellonif5aba912016-02-26 19:18:22 +01001326static int kszphy_resume(struct phy_device *phydev)
1327{
Leonard Crestez79e498a2017-05-31 13:29:30 +03001328 int ret;
1329
Wenyou Yang836384d2016-08-05 14:35:41 +08001330 genphy_resume(phydev);
Alexandre Bellonif5aba912016-02-26 19:18:22 +01001331
Oleksij Rempel6110dff2020-04-03 09:53:25 +02001332 /* After switching from power-down to normal mode, an internal global
1333 * reset is automatically generated. Wait a minimum of 1 ms before
1334 * read/write access to the PHY registers.
1335 */
1336 usleep_range(1000, 2000);
1337
Leonard Crestez79e498a2017-05-31 13:29:30 +03001338 ret = kszphy_config_reset(phydev);
1339 if (ret)
1340 return ret;
1341
Wenyou Yang836384d2016-08-05 14:35:41 +08001342 /* Enable PHY Interrupts */
1343 if (phy_interrupt_is_valid(phydev)) {
1344 phydev->interrupts = PHY_INTERRUPT_ENABLED;
1345 if (phydev->drv->config_intr)
1346 phydev->drv->config_intr(phydev);
1347 }
Alexandre Bellonif5aba912016-02-26 19:18:22 +01001348
1349 return 0;
1350}
1351
Johan Hovolde6a423a2014-11-19 12:59:15 +01001352static int kszphy_probe(struct phy_device *phydev)
1353{
1354 const struct kszphy_type *type = phydev->drv->driver_data;
Andrew Lunne5a03bf2016-01-06 20:11:16 +01001355 const struct device_node *np = phydev->mdio.dev.of_node;
Johan Hovolde6a423a2014-11-19 12:59:15 +01001356 struct kszphy_priv *priv;
Johan Hovold63f44b22014-11-19 12:59:18 +01001357 struct clk *clk;
Johan Hovolde7a792e2014-11-19 12:59:16 +01001358 int ret;
Johan Hovolde6a423a2014-11-19 12:59:15 +01001359
Andrew Lunne5a03bf2016-01-06 20:11:16 +01001360 priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
Johan Hovolde6a423a2014-11-19 12:59:15 +01001361 if (!priv)
1362 return -ENOMEM;
1363
1364 phydev->priv = priv;
1365
1366 priv->type = type;
1367
Johan Hovolde7a792e2014-11-19 12:59:16 +01001368 if (type->led_mode_reg) {
1369 ret = of_property_read_u32(np, "micrel,led-mode",
1370 &priv->led_mode);
1371 if (ret)
1372 priv->led_mode = -1;
1373
1374 if (priv->led_mode > 3) {
Andrew Lunn72ba48b2016-01-06 20:11:09 +01001375 phydev_err(phydev, "invalid led mode: 0x%02x\n",
1376 priv->led_mode);
Johan Hovolde7a792e2014-11-19 12:59:16 +01001377 priv->led_mode = -1;
1378 }
1379 } else {
1380 priv->led_mode = -1;
1381 }
1382
Andrew Lunne5a03bf2016-01-06 20:11:16 +01001383 clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
Niklas Casselbced8702015-05-12 09:43:14 +02001384 /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
1385 if (!IS_ERR_OR_NULL(clk)) {
Sascha Hauer1fadee02014-10-10 09:48:05 +02001386 unsigned long rate = clk_get_rate(clk);
Johan Hovold86dc1342014-11-19 12:59:19 +01001387 bool rmii_ref_clk_sel_25_mhz;
Sascha Hauer1fadee02014-10-10 09:48:05 +02001388
Johan Hovold63f44b22014-11-19 12:59:18 +01001389 priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel;
Johan Hovold86dc1342014-11-19 12:59:19 +01001390 rmii_ref_clk_sel_25_mhz = of_property_read_bool(np,
1391 "micrel,rmii-reference-clock-select-25-mhz");
Johan Hovold63f44b22014-11-19 12:59:18 +01001392
Sascha Hauer1fadee02014-10-10 09:48:05 +02001393 if (rate > 24500000 && rate < 25500000) {
Johan Hovold86dc1342014-11-19 12:59:19 +01001394 priv->rmii_ref_clk_sel_val = rmii_ref_clk_sel_25_mhz;
Sascha Hauer1fadee02014-10-10 09:48:05 +02001395 } else if (rate > 49500000 && rate < 50500000) {
Johan Hovold86dc1342014-11-19 12:59:19 +01001396 priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz;
Sascha Hauer1fadee02014-10-10 09:48:05 +02001397 } else {
Andrew Lunn72ba48b2016-01-06 20:11:09 +01001398 phydev_err(phydev, "Clock rate out of range: %ld\n",
1399 rate);
Sascha Hauer1fadee02014-10-10 09:48:05 +02001400 return -EINVAL;
1401 }
1402 }
1403
Michael Walle4217a642021-02-09 17:38:52 +01001404 if (ksz8041_fiber_mode(phydev))
1405 phydev->port = PORT_FIBRE;
1406
Johan Hovold63f44b22014-11-19 12:59:18 +01001407 /* Support legacy board-file configuration */
1408 if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
1409 priv->rmii_ref_clk_sel = true;
1410 priv->rmii_ref_clk_sel_val = true;
1411 }
1412
1413 return 0;
Sascha Hauer1fadee02014-10-10 09:48:05 +02001414}
1415
Oleksij Rempel49011e02021-06-14 06:31:25 +02001416static int ksz886x_cable_test_start(struct phy_device *phydev)
1417{
1418 if (phydev->dev_flags & MICREL_KSZ8_P1_ERRATA)
1419 return -EOPNOTSUPP;
1420
1421 /* If autoneg is enabled, we won't be able to test cross pair
1422 * short. In this case, the PHY will "detect" a link and
1423 * confuse the internal state machine - disable auto neg here.
1424 * If autoneg is disabled, we should set the speed to 10mbit.
1425 */
1426 return phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE | BMCR_SPEED100);
1427}
1428
1429static int ksz886x_cable_test_result_trans(u16 status)
1430{
1431 switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) {
1432 case KSZ8081_LMD_STAT_NORMAL:
1433 return ETHTOOL_A_CABLE_RESULT_CODE_OK;
1434 case KSZ8081_LMD_STAT_SHORT:
1435 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
1436 case KSZ8081_LMD_STAT_OPEN:
1437 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
1438 case KSZ8081_LMD_STAT_FAIL:
1439 fallthrough;
1440 default:
1441 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
1442 }
1443}
1444
1445static bool ksz886x_cable_test_failed(u16 status)
1446{
1447 return FIELD_GET(KSZ8081_LMD_STAT_MASK, status) ==
1448 KSZ8081_LMD_STAT_FAIL;
1449}
1450
1451static bool ksz886x_cable_test_fault_length_valid(u16 status)
1452{
1453 switch (FIELD_GET(KSZ8081_LMD_STAT_MASK, status)) {
1454 case KSZ8081_LMD_STAT_OPEN:
1455 fallthrough;
1456 case KSZ8081_LMD_STAT_SHORT:
1457 return true;
1458 }
1459 return false;
1460}
1461
1462static int ksz886x_cable_test_fault_length(u16 status)
1463{
1464 int dt;
1465
1466 /* According to the data sheet the distance to the fault is
1467 * DELTA_TIME * 0.4 meters.
1468 */
1469 dt = FIELD_GET(KSZ8081_LMD_DELTA_TIME_MASK, status);
1470
1471 return (dt * 400) / 10;
1472}
1473
1474static int ksz886x_cable_test_wait_for_completion(struct phy_device *phydev)
1475{
1476 int val, ret;
1477
1478 ret = phy_read_poll_timeout(phydev, KSZ8081_LMD, val,
1479 !(val & KSZ8081_LMD_ENABLE_TEST),
1480 30000, 100000, true);
1481
1482 return ret < 0 ? ret : 0;
1483}
1484
1485static int ksz886x_cable_test_one_pair(struct phy_device *phydev, int pair)
1486{
1487 static const int ethtool_pair[] = {
1488 ETHTOOL_A_CABLE_PAIR_A,
1489 ETHTOOL_A_CABLE_PAIR_B,
1490 };
1491 int ret, val, mdix;
1492
1493 /* There is no way to choice the pair, like we do one ksz9031.
1494 * We can workaround this limitation by using the MDI-X functionality.
1495 */
1496 if (pair == 0)
1497 mdix = ETH_TP_MDI;
1498 else
1499 mdix = ETH_TP_MDI_X;
1500
1501 switch (phydev->phy_id & MICREL_PHY_ID_MASK) {
1502 case PHY_ID_KSZ8081:
1503 ret = ksz8081_config_mdix(phydev, mdix);
1504 break;
1505 case PHY_ID_KSZ886X:
1506 ret = ksz886x_config_mdix(phydev, mdix);
1507 break;
1508 default:
1509 ret = -ENODEV;
1510 }
1511
1512 if (ret)
1513 return ret;
1514
1515 /* Now we are ready to fire. This command will send a 100ns pulse
1516 * to the pair.
1517 */
1518 ret = phy_write(phydev, KSZ8081_LMD, KSZ8081_LMD_ENABLE_TEST);
1519 if (ret)
1520 return ret;
1521
1522 ret = ksz886x_cable_test_wait_for_completion(phydev);
1523 if (ret)
1524 return ret;
1525
1526 val = phy_read(phydev, KSZ8081_LMD);
1527 if (val < 0)
1528 return val;
1529
1530 if (ksz886x_cable_test_failed(val))
1531 return -EAGAIN;
1532
1533 ret = ethnl_cable_test_result(phydev, ethtool_pair[pair],
1534 ksz886x_cable_test_result_trans(val));
1535 if (ret)
1536 return ret;
1537
1538 if (!ksz886x_cable_test_fault_length_valid(val))
1539 return 0;
1540
1541 return ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
1542 ksz886x_cable_test_fault_length(val));
1543}
1544
1545static int ksz886x_cable_test_get_status(struct phy_device *phydev,
1546 bool *finished)
1547{
1548 unsigned long pair_mask = 0x3;
1549 int retries = 20;
1550 int pair, ret;
1551
1552 *finished = false;
1553
1554 /* Try harder if link partner is active */
1555 while (pair_mask && retries--) {
1556 for_each_set_bit(pair, &pair_mask, 4) {
1557 ret = ksz886x_cable_test_one_pair(phydev, pair);
1558 if (ret == -EAGAIN)
1559 continue;
1560 if (ret < 0)
1561 return ret;
1562 clear_bit(pair, &pair_mask);
1563 }
1564 /* If link partner is in autonegotiation mode it will send 2ms
1565 * of FLPs with at least 6ms of silence.
1566 * Add 2ms sleep to have better chances to hit this silence.
1567 */
1568 if (pair_mask)
1569 msleep(2);
1570 }
1571
1572 *finished = true;
1573
1574 return ret;
1575}
1576
Horatiu Vultur7c2dcfa2021-09-28 20:45:19 +02001577#define LAN_EXT_PAGE_ACCESS_CONTROL 0x16
1578#define LAN_EXT_PAGE_ACCESS_ADDRESS_DATA 0x17
1579#define LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC 0x4000
1580
Horatiu Vultur7467d712021-12-23 09:28:26 +01001581#define LAN8814_QSGMII_SOFT_RESET 0x43
1582#define LAN8814_QSGMII_SOFT_RESET_BIT BIT(0)
1583#define LAN8814_QSGMII_PCS1G_ANEG_CONFIG 0x13
1584#define LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA BIT(3)
1585#define LAN8814_ALIGN_SWAP 0x4a
1586#define LAN8814_ALIGN_TX_A_B_SWAP 0x1
1587#define LAN8814_ALIGN_TX_A_B_SWAP_MASK GENMASK(2, 0)
1588
Horatiu Vultur7c2dcfa2021-09-28 20:45:19 +02001589#define LAN8804_ALIGN_SWAP 0x4a
1590#define LAN8804_ALIGN_TX_A_B_SWAP 0x1
1591#define LAN8804_ALIGN_TX_A_B_SWAP_MASK GENMASK(2, 0)
1592#define LAN8814_CLOCK_MANAGEMENT 0xd
1593#define LAN8814_LINK_QUALITY 0x8e
1594
1595static int lanphy_read_page_reg(struct phy_device *phydev, int page, u32 addr)
1596{
1597 u32 data;
1598
1599 phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
1600 phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
1601 phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
1602 (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
1603 data = phy_read(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA);
1604
1605 return data;
1606}
1607
1608static int lanphy_write_page_reg(struct phy_device *phydev, int page, u16 addr,
1609 u16 val)
1610{
1611 phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL, page);
1612 phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, addr);
1613 phy_write(phydev, LAN_EXT_PAGE_ACCESS_CONTROL,
1614 (page | LAN_EXT_PAGE_ACCESS_CTRL_EP_FUNC));
1615
1616 val = phy_write(phydev, LAN_EXT_PAGE_ACCESS_ADDRESS_DATA, val);
1617 if (val) {
1618 phydev_err(phydev, "Error: phy_write has returned error %d\n",
1619 val);
1620 return val;
1621 }
1622 return 0;
1623}
1624
Horatiu Vultur7467d712021-12-23 09:28:26 +01001625static int lan8814_config_init(struct phy_device *phydev)
1626{
1627 int val;
1628
1629 /* Reset the PHY */
1630 val = lanphy_read_page_reg(phydev, 4, LAN8814_QSGMII_SOFT_RESET);
1631 val |= LAN8814_QSGMII_SOFT_RESET_BIT;
1632 lanphy_write_page_reg(phydev, 4, LAN8814_QSGMII_SOFT_RESET, val);
1633
1634 /* Disable ANEG with QSGMII PCS Host side */
1635 val = lanphy_read_page_reg(phydev, 5, LAN8814_QSGMII_PCS1G_ANEG_CONFIG);
1636 val &= ~LAN8814_QSGMII_PCS1G_ANEG_CONFIG_ANEG_ENA;
1637 lanphy_write_page_reg(phydev, 5, LAN8814_QSGMII_PCS1G_ANEG_CONFIG, val);
1638
1639 /* MDI-X setting for swap A,B transmit */
1640 val = lanphy_read_page_reg(phydev, 2, LAN8814_ALIGN_SWAP);
1641 val &= ~LAN8814_ALIGN_TX_A_B_SWAP_MASK;
1642 val |= LAN8814_ALIGN_TX_A_B_SWAP;
1643 lanphy_write_page_reg(phydev, 2, LAN8814_ALIGN_SWAP, val);
1644
1645 return 0;
1646}
1647
Horatiu Vultur7c2dcfa2021-09-28 20:45:19 +02001648static int lan8804_config_init(struct phy_device *phydev)
1649{
1650 int val;
1651
1652 /* MDI-X setting for swap A,B transmit */
1653 val = lanphy_read_page_reg(phydev, 2, LAN8804_ALIGN_SWAP);
1654 val &= ~LAN8804_ALIGN_TX_A_B_SWAP_MASK;
1655 val |= LAN8804_ALIGN_TX_A_B_SWAP;
1656 lanphy_write_page_reg(phydev, 2, LAN8804_ALIGN_SWAP, val);
1657
1658 /* Make sure that the PHY will not stop generating the clock when the
1659 * link partner goes down
1660 */
1661 lanphy_write_page_reg(phydev, 31, LAN8814_CLOCK_MANAGEMENT, 0x27e);
1662 lanphy_read_page_reg(phydev, 1, LAN8814_LINK_QUALITY);
1663
1664 return 0;
1665}
1666
Divya Kopperab3ec7242021-12-21 16:52:17 +05301667static irqreturn_t lan8814_handle_interrupt(struct phy_device *phydev)
1668{
1669 int irq_status;
1670
1671 irq_status = phy_read(phydev, LAN8814_INTS);
1672 if (irq_status < 0)
1673 return IRQ_NONE;
1674
1675 if (!(irq_status & LAN8814_INT_LINK))
1676 return IRQ_NONE;
1677
1678 phy_trigger_machine(phydev);
1679
1680 return IRQ_HANDLED;
1681}
1682
1683static int lan8814_ack_interrupt(struct phy_device *phydev)
1684{
1685 /* bit[12..0] int status, which is a read and clear register. */
1686 int rc;
1687
1688 rc = phy_read(phydev, LAN8814_INTS);
1689
1690 return (rc < 0) ? rc : 0;
1691}
1692
1693static int lan8814_config_intr(struct phy_device *phydev)
1694{
1695 int err;
1696
1697 lanphy_write_page_reg(phydev, 4, LAN8814_INTR_CTRL_REG,
1698 LAN8814_INTR_CTRL_REG_POLARITY |
1699 LAN8814_INTR_CTRL_REG_INTR_ENABLE);
1700
1701 /* enable / disable interrupts */
1702 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1703 err = lan8814_ack_interrupt(phydev);
1704 if (err)
1705 return err;
1706
1707 err = phy_write(phydev, LAN8814_INTC, LAN8814_INT_LINK);
1708 } else {
1709 err = phy_write(phydev, LAN8814_INTC, 0);
1710 if (err)
1711 return err;
1712
1713 err = lan8814_ack_interrupt(phydev);
1714 }
1715
1716 return err;
1717}
1718
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001719static struct phy_driver ksphy_driver[] = {
1720{
Choi, David51f932c2010-06-28 15:23:41 +00001721 .phy_id = PHY_ID_KS8737,
Fabio Estevamf893a992016-05-11 17:02:05 -03001722 .phy_id_mask = MICREL_PHY_ID_MASK,
Choi, David51f932c2010-06-28 15:23:41 +00001723 .name = "Micrel KS8737",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001724 /* PHY_BASIC_FEATURES */
Johan Hovoldc6f95752014-11-19 12:59:22 +01001725 .driver_data = &ks8737_type,
David J. Choid0507002010-04-29 06:12:41 +00001726 .config_init = kszphy_config_init,
Johan Hovoldc6f95752014-11-19 12:59:22 +01001727 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001728 .handle_interrupt = kszphy_handle_interrupt,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001729 .suspend = kszphy_suspend,
1730 .resume = kszphy_resume,
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001731}, {
Marek Vasut212ea992012-09-23 16:58:49 +00001732 .phy_id = PHY_ID_KSZ8021,
1733 .phy_id_mask = 0x00ffffff,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001734 .name = "Micrel KSZ8021 or KSZ8031",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001735 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001736 .driver_data = &ksz8021_type,
Johan Hovold63f44b22014-11-19 12:59:18 +01001737 .probe = kszphy_probe,
Johan Hovoldd0e1df92014-12-23 12:59:17 +01001738 .config_init = kszphy_config_init,
Marek Vasut212ea992012-09-23 16:58:49 +00001739 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001740 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001741 .get_sset_count = kszphy_get_sset_count,
1742 .get_strings = kszphy_get_strings,
1743 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001744 .suspend = kszphy_suspend,
1745 .resume = kszphy_resume,
Marek Vasut212ea992012-09-23 16:58:49 +00001746}, {
Hector Palaciosb818d1a2013-03-10 22:50:02 +00001747 .phy_id = PHY_ID_KSZ8031,
1748 .phy_id_mask = 0x00ffffff,
1749 .name = "Micrel KSZ8031",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001750 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001751 .driver_data = &ksz8021_type,
Johan Hovold63f44b22014-11-19 12:59:18 +01001752 .probe = kszphy_probe,
Johan Hovoldd0e1df92014-12-23 12:59:17 +01001753 .config_init = kszphy_config_init,
Hector Palaciosb818d1a2013-03-10 22:50:02 +00001754 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001755 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001756 .get_sset_count = kszphy_get_sset_count,
1757 .get_strings = kszphy_get_strings,
1758 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001759 .suspend = kszphy_suspend,
1760 .resume = kszphy_resume,
Hector Palaciosb818d1a2013-03-10 22:50:02 +00001761}, {
Marek Vasut510d5732012-09-23 16:58:50 +00001762 .phy_id = PHY_ID_KSZ8041,
Fabio Estevamf893a992016-05-11 17:02:05 -03001763 .phy_id_mask = MICREL_PHY_ID_MASK,
Marek Vasut510d5732012-09-23 16:58:50 +00001764 .name = "Micrel KSZ8041",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001765 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001766 .driver_data = &ksz8041_type,
1767 .probe = kszphy_probe,
Philipp Zabel77501a72016-07-14 16:29:43 +02001768 .config_init = ksz8041_config_init,
1769 .config_aneg = ksz8041_config_aneg,
Choi, David51f932c2010-06-28 15:23:41 +00001770 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001771 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001772 .get_sset_count = kszphy_get_sset_count,
1773 .get_strings = kszphy_get_strings,
1774 .get_stats = kszphy_get_stats,
Stefan Agner2641b622021-10-19 21:16:47 +02001775 /* No suspend/resume callbacks because of errata DS80000700A,
1776 * receiver error following software power down.
1777 */
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001778}, {
Sergei Shtylyov4bd7b512013-12-10 02:20:41 +03001779 .phy_id = PHY_ID_KSZ8041RNLI,
Fabio Estevamf893a992016-05-11 17:02:05 -03001780 .phy_id_mask = MICREL_PHY_ID_MASK,
Sergei Shtylyov4bd7b512013-12-10 02:20:41 +03001781 .name = "Micrel KSZ8041RNLI",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001782 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001783 .driver_data = &ksz8041_type,
1784 .probe = kszphy_probe,
1785 .config_init = kszphy_config_init,
Sergei Shtylyov4bd7b512013-12-10 02:20:41 +03001786 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001787 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001788 .get_sset_count = kszphy_get_sset_count,
1789 .get_strings = kszphy_get_strings,
1790 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001791 .suspend = kszphy_suspend,
1792 .resume = kszphy_resume,
Sergei Shtylyov4bd7b512013-12-10 02:20:41 +03001793}, {
Marek Vasut510d5732012-09-23 16:58:50 +00001794 .name = "Micrel KSZ8051",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001795 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001796 .driver_data = &ksz8051_type,
1797 .probe = kszphy_probe,
Johan Hovold63f44b22014-11-19 12:59:18 +01001798 .config_init = kszphy_config_init,
Choi, David51f932c2010-06-28 15:23:41 +00001799 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001800 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001801 .get_sset_count = kszphy_get_sset_count,
1802 .get_strings = kszphy_get_strings,
1803 .get_stats = kszphy_get_stats,
Marek Vasut8b955992019-10-16 15:35:06 +02001804 .match_phy_device = ksz8051_match_phy_device,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001805 .suspend = kszphy_suspend,
1806 .resume = kszphy_resume,
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001807}, {
Marek Vasut510d5732012-09-23 16:58:50 +00001808 .phy_id = PHY_ID_KSZ8001,
1809 .name = "Micrel KSZ8001 or KS8721",
Alexander Steinecd5a322016-07-29 12:12:08 +02001810 .phy_id_mask = 0x00fffffc,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001811 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001812 .driver_data = &ksz8041_type,
1813 .probe = kszphy_probe,
1814 .config_init = kszphy_config_init,
Choi, David51f932c2010-06-28 15:23:41 +00001815 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001816 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001817 .get_sset_count = kszphy_get_sset_count,
1818 .get_strings = kszphy_get_strings,
1819 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001820 .suspend = kszphy_suspend,
1821 .resume = kszphy_resume,
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001822}, {
David J. Choi7ab59dc2013-01-23 14:05:15 +00001823 .phy_id = PHY_ID_KSZ8081,
1824 .name = "Micrel KSZ8081 or KSZ8091",
Fabio Estevamf893a992016-05-11 17:02:05 -03001825 .phy_id_mask = MICREL_PHY_ID_MASK,
Oleksij Rempel49011e02021-06-14 06:31:25 +02001826 .flags = PHY_POLL_CABLE_TEST,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001827 /* PHY_BASIC_FEATURES */
Johan Hovolde6a423a2014-11-19 12:59:15 +01001828 .driver_data = &ksz8081_type,
1829 .probe = kszphy_probe,
Antoine Tenart7a1d8392019-04-26 18:41:23 +02001830 .config_init = ksz8081_config_init,
Christian Melki764d31c2021-02-24 21:55:36 +01001831 .soft_reset = genphy_soft_reset,
Oleksij Rempelf873f112021-06-14 06:31:22 +02001832 .config_aneg = ksz8081_config_aneg,
1833 .read_status = ksz8081_read_status,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001834 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001835 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001836 .get_sset_count = kszphy_get_sset_count,
1837 .get_strings = kszphy_get_strings,
1838 .get_stats = kszphy_get_stats,
Wenyou Yang836384d2016-08-05 14:35:41 +08001839 .suspend = kszphy_suspend,
Alexandre Bellonif5aba912016-02-26 19:18:22 +01001840 .resume = kszphy_resume,
Oleksij Rempel49011e02021-06-14 06:31:25 +02001841 .cable_test_start = ksz886x_cable_test_start,
1842 .cable_test_get_status = ksz886x_cable_test_get_status,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001843}, {
1844 .phy_id = PHY_ID_KSZ8061,
1845 .name = "Micrel KSZ8061",
Fabio Estevamf893a992016-05-11 17:02:05 -03001846 .phy_id_mask = MICREL_PHY_ID_MASK,
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001847 /* PHY_BASIC_FEATURES */
Rajasingh Thavamani232ba3a2019-02-27 17:43:19 +05301848 .config_init = ksz8061_config_init,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001849 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001850 .handle_interrupt = kszphy_handle_interrupt,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001851 .suspend = kszphy_suspend,
1852 .resume = kszphy_resume,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001853}, {
David J. Choid0507002010-04-29 06:12:41 +00001854 .phy_id = PHY_ID_KSZ9021,
Jason Wang48d7d0a2012-06-17 22:52:09 +00001855 .phy_id_mask = 0x000ffffe,
David J. Choid0507002010-04-29 06:12:41 +00001856 .name = "Micrel KSZ9021 Gigabit PHY",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001857 /* PHY_GBIT_FEATURES */
Johan Hovoldc6f95752014-11-19 12:59:22 +01001858 .driver_data = &ksz9021_type,
Grygorii Strashkobfe72442017-04-13 14:11:27 -05001859 .probe = kszphy_probe,
Hans Andersson407d8092019-09-26 09:54:37 +02001860 .get_features = ksz9031_get_features,
Sean Cross954c3962013-08-21 01:46:12 +00001861 .config_init = ksz9021_config_init,
Johan Hovoldc6f95752014-11-19 12:59:22 +01001862 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001863 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001864 .get_sset_count = kszphy_get_sset_count,
1865 .get_strings = kszphy_get_strings,
1866 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001867 .suspend = kszphy_suspend,
1868 .resume = kszphy_resume,
Kevin Haoc846a2b2018-03-20 09:44:54 +08001869 .read_mmd = genphy_read_mmd_unsupported,
1870 .write_mmd = genphy_write_mmd_unsupported,
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001871}, {
David J. Choi7ab59dc2013-01-23 14:05:15 +00001872 .phy_id = PHY_ID_KSZ9031,
Fabio Estevamf893a992016-05-11 17:02:05 -03001873 .phy_id_mask = MICREL_PHY_ID_MASK,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001874 .name = "Micrel KSZ9031 Gigabit PHY",
Johan Hovoldc6f95752014-11-19 12:59:22 +01001875 .driver_data = &ksz9021_type,
Grygorii Strashkobfe72442017-04-13 14:11:27 -05001876 .probe = kszphy_probe,
Antoine Tenart3aed3e22019-04-16 12:10:20 +02001877 .get_features = ksz9031_get_features,
Hubert Chaumette6e4b8272014-05-06 09:40:17 +02001878 .config_init = ksz9031_config_init,
Heiner Kallweit1d160732019-01-10 20:22:26 +01001879 .soft_reset = genphy_soft_reset,
Nathan Sullivand2fd7192015-10-21 14:17:04 -05001880 .read_status = ksz9031_read_status,
Johan Hovoldc6f95752014-11-19 12:59:22 +01001881 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001882 .handle_interrupt = kszphy_handle_interrupt,
Andrew Lunn2b2427d2015-12-30 16:28:27 +01001883 .get_sset_count = kszphy_get_sset_count,
1884 .get_strings = kszphy_get_strings,
1885 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001886 .suspend = kszphy_suspend,
Xander Hufff64f1482016-08-22 15:57:16 -05001887 .resume = kszphy_resume,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001888}, {
Divya Koppera1623ad82020-09-11 18:48:44 +05301889 .phy_id = PHY_ID_LAN8814,
1890 .phy_id_mask = MICREL_PHY_ID_MASK,
1891 .name = "Microchip INDY Gigabit Quad PHY",
Horatiu Vultur7467d712021-12-23 09:28:26 +01001892 .config_init = lan8814_config_init,
Divya Koppera1623ad82020-09-11 18:48:44 +05301893 .driver_data = &ksz9021_type,
1894 .probe = kszphy_probe,
1895 .soft_reset = genphy_soft_reset,
1896 .read_status = ksz9031_read_status,
1897 .get_sset_count = kszphy_get_sset_count,
1898 .get_strings = kszphy_get_strings,
1899 .get_stats = kszphy_get_stats,
1900 .suspend = genphy_suspend,
1901 .resume = kszphy_resume,
Divya Kopperab3ec7242021-12-21 16:52:17 +05301902 .config_intr = lan8814_config_intr,
1903 .handle_interrupt = lan8814_handle_interrupt,
Divya Koppera1623ad82020-09-11 18:48:44 +05301904}, {
Horatiu Vultur7c2dcfa2021-09-28 20:45:19 +02001905 .phy_id = PHY_ID_LAN8804,
1906 .phy_id_mask = MICREL_PHY_ID_MASK,
1907 .name = "Microchip LAN966X Gigabit PHY",
1908 .config_init = lan8804_config_init,
1909 .driver_data = &ksz9021_type,
1910 .probe = kszphy_probe,
1911 .soft_reset = genphy_soft_reset,
1912 .read_status = ksz9031_read_status,
1913 .get_sset_count = kszphy_get_sset_count,
1914 .get_strings = kszphy_get_strings,
1915 .get_stats = kszphy_get_stats,
1916 .suspend = genphy_suspend,
1917 .resume = kszphy_resume,
1918}, {
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001919 .phy_id = PHY_ID_KSZ9131,
1920 .phy_id_mask = MICREL_PHY_ID_MASK,
1921 .name = "Microchip KSZ9131 Gigabit PHY",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001922 /* PHY_GBIT_FEATURES */
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001923 .driver_data = &ksz9021_type,
1924 .probe = kszphy_probe,
1925 .config_init = ksz9131_config_init,
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001926 .config_intr = kszphy_config_intr,
Ioana Ciornei59ca4e52020-11-23 17:38:09 +02001927 .handle_interrupt = kszphy_handle_interrupt,
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001928 .get_sset_count = kszphy_get_sset_count,
1929 .get_strings = kszphy_get_strings,
1930 .get_stats = kszphy_get_stats,
Claudiu Bezneaf1131b92022-01-18 13:08:12 +02001931 .suspend = kszphy_suspend,
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001932 .resume = kszphy_resume,
1933}, {
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001934 .phy_id = PHY_ID_KSZ8873MLL,
Fabio Estevamf893a992016-05-11 17:02:05 -03001935 .phy_id_mask = MICREL_PHY_ID_MASK,
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001936 .name = "Micrel KSZ8873MLL Switch",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001937 /* PHY_BASIC_FEATURES */
Jean-Christophe PLAGNIOL-VILLARD93272e02012-11-21 05:38:07 +00001938 .config_init = kszphy_config_init,
1939 .config_aneg = ksz8873mll_config_aneg,
1940 .read_status = ksz8873mll_read_status,
Patrice Vilchez1a5465f2013-09-19 19:40:48 +02001941 .suspend = genphy_suspend,
1942 .resume = genphy_resume,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001943}, {
1944 .phy_id = PHY_ID_KSZ886X,
Fabio Estevamf893a992016-05-11 17:02:05 -03001945 .phy_id_mask = MICREL_PHY_ID_MASK,
Marek Vasutab36a3a2021-01-05 15:11:50 +01001946 .name = "Micrel KSZ8851 Ethernet MAC or KSZ886X Switch",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001947 /* PHY_BASIC_FEATURES */
Oleksij Rempel49011e02021-06-14 06:31:25 +02001948 .flags = PHY_POLL_CABLE_TEST,
David J. Choi7ab59dc2013-01-23 14:05:15 +00001949 .config_init = kszphy_config_init,
Oleksij Rempel52939392021-06-14 06:31:21 +02001950 .config_aneg = ksz886x_config_aneg,
1951 .read_status = ksz886x_read_status,
Patrice Vilchez1a5465f2013-09-19 19:40:48 +02001952 .suspend = genphy_suspend,
1953 .resume = genphy_resume,
Oleksij Rempel49011e02021-06-14 06:31:25 +02001954 .cable_test_start = ksz886x_cable_test_start,
1955 .cable_test_get_status = ksz886x_cable_test_get_status,
Sean Nyekjaer9d162ed2017-01-27 08:46:23 +01001956}, {
Marek Vasut1d951ba2019-10-16 15:35:07 +02001957 .name = "Micrel KSZ87XX Switch",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001958 /* PHY_BASIC_FEATURES */
Sean Nyekjaer9d162ed2017-01-27 08:46:23 +01001959 .config_init = kszphy_config_init,
Marek Vasut8b955992019-10-16 15:35:06 +02001960 .match_phy_device = ksz8795_match_phy_device,
Sean Nyekjaer9d162ed2017-01-27 08:46:23 +01001961 .suspend = genphy_suspend,
1962 .resume = genphy_resume,
Woojung Huhfc3973a2017-05-31 20:19:13 +00001963}, {
1964 .phy_id = PHY_ID_KSZ9477,
1965 .phy_id_mask = MICREL_PHY_ID_MASK,
1966 .name = "Microchip KSZ9477",
Heiner Kallweitdcdecdc2019-04-12 20:47:03 +02001967 /* PHY_GBIT_FEATURES */
Woojung Huhfc3973a2017-05-31 20:19:13 +00001968 .config_init = kszphy_config_init,
Woojung Huhfc3973a2017-05-31 20:19:13 +00001969 .suspend = genphy_suspend,
1970 .resume = genphy_resume,
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +00001971} };
David J. Choid0507002010-04-29 06:12:41 +00001972
Johan Hovold50fd7152014-11-11 19:45:59 +01001973module_phy_driver(ksphy_driver);
David J. Choid0507002010-04-29 06:12:41 +00001974
1975MODULE_DESCRIPTION("Micrel PHY driver");
1976MODULE_AUTHOR("David J. Choi");
1977MODULE_LICENSE("GPL");
David S. Miller52a60ed2010-05-03 15:48:29 -07001978
Uwe Kleine-Königcf93c942010-10-03 23:43:32 +00001979static struct mdio_device_id __maybe_unused micrel_tbl[] = {
Jason Wang48d7d0a2012-06-17 22:52:09 +00001980 { PHY_ID_KSZ9021, 0x000ffffe },
Fabio Estevamf893a992016-05-11 17:02:05 -03001981 { PHY_ID_KSZ9031, MICREL_PHY_ID_MASK },
Yuiko Oshinobff5b4b2018-10-18 15:06:01 -04001982 { PHY_ID_KSZ9131, MICREL_PHY_ID_MASK },
Alexander Steinecd5a322016-07-29 12:12:08 +02001983 { PHY_ID_KSZ8001, 0x00fffffc },
Fabio Estevamf893a992016-05-11 17:02:05 -03001984 { PHY_ID_KS8737, MICREL_PHY_ID_MASK },
Marek Vasut212ea992012-09-23 16:58:49 +00001985 { PHY_ID_KSZ8021, 0x00ffffff },
Hector Palaciosb818d1a2013-03-10 22:50:02 +00001986 { PHY_ID_KSZ8031, 0x00ffffff },
Fabio Estevamf893a992016-05-11 17:02:05 -03001987 { PHY_ID_KSZ8041, MICREL_PHY_ID_MASK },
1988 { PHY_ID_KSZ8051, MICREL_PHY_ID_MASK },
1989 { PHY_ID_KSZ8061, MICREL_PHY_ID_MASK },
1990 { PHY_ID_KSZ8081, MICREL_PHY_ID_MASK },
1991 { PHY_ID_KSZ8873MLL, MICREL_PHY_ID_MASK },
1992 { PHY_ID_KSZ886X, MICREL_PHY_ID_MASK },
Divya Koppera1623ad82020-09-11 18:48:44 +05301993 { PHY_ID_LAN8814, MICREL_PHY_ID_MASK },
Horatiu Vultur7c2dcfa2021-09-28 20:45:19 +02001994 { PHY_ID_LAN8804, MICREL_PHY_ID_MASK },
David S. Miller52a60ed2010-05-03 15:48:29 -07001995 { }
1996};
1997
1998MODULE_DEVICE_TABLE(mdio, micrel_tbl);