Skip to content

Commit 5dc39fd

Browse files
Dan Murphydavem330
authored andcommitted
net: phy: DP83822: Add ability to advertise Fiber connection
The DP83822 can be configured to use a Fiber connection. The strap register is read to determine if the device has been configured to use a fiber connection. With the fiber connection the PHY can be configured to detect whether the fiber connection is active by either a high signal or a low signal. Fiber mode is only applicable to the DP83822 so rework the PHY match table so that non-fiber PHYs can still use the same driver but not call or use any of the fiber features. Signed-off-by: Dan Murphy <dmurphy@ti.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 7a63d76 commit 5dc39fd

File tree

1 file changed

+218
-7
lines changed

1 file changed

+218
-7
lines changed

drivers/net/phy/dp83822.c

Lines changed: 218 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,31 @@
2323

2424
#define DP83822_DEVADDR 0x1f
2525

26+
#define MII_DP83822_CTRL_2 0x0a
27+
#define MII_DP83822_PHYSTS 0x10
2628
#define MII_DP83822_PHYSCR 0x11
2729
#define MII_DP83822_MISR1 0x12
2830
#define MII_DP83822_MISR2 0x13
31+
#define MII_DP83822_FCSCR 0x14
2932
#define MII_DP83822_RCSR 0x17
3033
#define MII_DP83822_RESET_CTRL 0x1f
3134
#define MII_DP83822_GENCFG 0x465
35+
#define MII_DP83822_SOR1 0x467
36+
37+
/* GENCFG */
38+
#define DP83822_SIG_DET_LOW BIT(0)
39+
40+
/* Control Register 2 bits */
41+
#define DP83822_FX_ENABLE BIT(14)
3242

3343
#define DP83822_HW_RESET BIT(15)
3444
#define DP83822_SW_RESET BIT(14)
3545

46+
/* PHY STS bits */
47+
#define DP83822_PHYSTS_DUPLEX BIT(2)
48+
#define DP83822_PHYSTS_10 BIT(1)
49+
#define DP83822_PHYSTS_LINK BIT(0)
50+
3651
/* PHYSCR Register Fields */
3752
#define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */
3853
#define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */
@@ -83,6 +98,28 @@
8398
#define DP83822_RX_CLK_SHIFT BIT(12)
8499
#define DP83822_TX_CLK_SHIFT BIT(11)
85100

101+
/* SOR1 mode */
102+
#define DP83822_STRAP_MODE1 0
103+
#define DP83822_STRAP_MODE2 BIT(0)
104+
#define DP83822_STRAP_MODE3 BIT(1)
105+
#define DP83822_STRAP_MODE4 GENMASK(1, 0)
106+
107+
#define DP83822_COL_STRAP_MASK GENMASK(11, 10)
108+
#define DP83822_COL_SHIFT 10
109+
#define DP83822_RX_ER_STR_MASK GENMASK(9, 8)
110+
#define DP83822_RX_ER_SHIFT 8
111+
112+
#define MII_DP83822_FIBER_ADVERTISE (ADVERTISED_TP | ADVERTISED_MII | \
113+
ADVERTISED_FIBRE | ADVERTISED_BNC | \
114+
ADVERTISED_Pause | ADVERTISED_Asym_Pause | \
115+
ADVERTISED_100baseT_Full)
116+
117+
struct dp83822_private {
118+
bool fx_signal_det_low;
119+
int fx_enabled;
120+
u16 fx_sd_enable;
121+
};
122+
86123
static int dp83822_ack_interrupt(struct phy_device *phydev)
87124
{
88125
int err;
@@ -197,6 +234,7 @@ static void dp83822_get_wol(struct phy_device *phydev,
197234

198235
static int dp83822_config_intr(struct phy_device *phydev)
199236
{
237+
struct dp83822_private *dp83822 = phydev->priv;
200238
int misr_status;
201239
int physcr_status;
202240
int err;
@@ -208,13 +246,16 @@ static int dp83822_config_intr(struct phy_device *phydev)
208246

209247
misr_status |= (DP83822_RX_ERR_HF_INT_EN |
210248
DP83822_FALSE_CARRIER_HF_INT_EN |
211-
DP83822_ANEG_COMPLETE_INT_EN |
212-
DP83822_DUP_MODE_CHANGE_INT_EN |
213-
DP83822_SPEED_CHANGED_INT_EN |
214249
DP83822_LINK_STAT_INT_EN |
215250
DP83822_ENERGY_DET_INT_EN |
216251
DP83822_LINK_QUAL_INT_EN);
217252

253+
if (!dp83822->fx_enabled)
254+
misr_status |= DP83822_ANEG_COMPLETE_INT_EN |
255+
DP83822_DUP_MODE_CHANGE_INT_EN |
256+
DP83822_SPEED_CHANGED_INT_EN;
257+
258+
218259
err = phy_write(phydev, MII_DP83822_MISR1, misr_status);
219260
if (err < 0)
220261
return err;
@@ -224,14 +265,16 @@ static int dp83822_config_intr(struct phy_device *phydev)
224265
return misr_status;
225266

226267
misr_status |= (DP83822_JABBER_DET_INT_EN |
227-
DP83822_WOL_PKT_INT_EN |
228268
DP83822_SLEEP_MODE_INT_EN |
229-
DP83822_MDI_XOVER_INT_EN |
230269
DP83822_LB_FIFO_INT_EN |
231270
DP83822_PAGE_RX_INT_EN |
232-
DP83822_ANEG_ERR_INT_EN |
233271
DP83822_EEE_ERROR_CHANGE_INT_EN);
234272

273+
if (!dp83822->fx_enabled)
274+
misr_status |= DP83822_MDI_XOVER_INT_EN |
275+
DP83822_ANEG_ERR_INT_EN |
276+
DP83822_WOL_PKT_INT_EN;
277+
235278
err = phy_write(phydev, MII_DP83822_MISR2, misr_status);
236279
if (err < 0)
237280
return err;
@@ -270,13 +313,60 @@ static int dp8382x_disable_wol(struct phy_device *phydev)
270313
MII_DP83822_WOL_CFG, value);
271314
}
272315

316+
static int dp83822_read_status(struct phy_device *phydev)
317+
{
318+
struct dp83822_private *dp83822 = phydev->priv;
319+
int status = phy_read(phydev, MII_DP83822_PHYSTS);
320+
int ctrl2;
321+
int ret;
322+
323+
if (dp83822->fx_enabled) {
324+
if (status & DP83822_PHYSTS_LINK) {
325+
phydev->speed = SPEED_UNKNOWN;
326+
phydev->duplex = DUPLEX_UNKNOWN;
327+
} else {
328+
ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2);
329+
if (ctrl2 < 0)
330+
return ctrl2;
331+
332+
if (!(ctrl2 & DP83822_FX_ENABLE)) {
333+
ret = phy_write(phydev, MII_DP83822_CTRL_2,
334+
DP83822_FX_ENABLE | ctrl2);
335+
if (ret < 0)
336+
return ret;
337+
}
338+
}
339+
}
340+
341+
ret = genphy_read_status(phydev);
342+
if (ret)
343+
return ret;
344+
345+
if (status < 0)
346+
return status;
347+
348+
if (status & DP83822_PHYSTS_DUPLEX)
349+
phydev->duplex = DUPLEX_FULL;
350+
else
351+
phydev->duplex = DUPLEX_HALF;
352+
353+
if (status & DP83822_PHYSTS_10)
354+
phydev->speed = SPEED_10;
355+
else
356+
phydev->speed = SPEED_100;
357+
358+
return 0;
359+
}
360+
273361
static int dp83822_config_init(struct phy_device *phydev)
274362
{
363+
struct dp83822_private *dp83822 = phydev->priv;
275364
struct device *dev = &phydev->mdio.dev;
276365
int rgmii_delay;
277366
s32 rx_int_delay;
278367
s32 tx_int_delay;
279368
int err = 0;
369+
int bmcr;
280370

281371
if (phy_interface_is_rgmii(phydev)) {
282372
rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
@@ -302,6 +392,53 @@ static int dp83822_config_init(struct phy_device *phydev)
302392
}
303393
}
304394

395+
if (dp83822->fx_enabled) {
396+
err = phy_modify(phydev, MII_DP83822_CTRL_2,
397+
DP83822_FX_ENABLE, 1);
398+
if (err < 0)
399+
return err;
400+
401+
/* Only allow advertising what this PHY supports */
402+
linkmode_and(phydev->advertising, phydev->advertising,
403+
phydev->supported);
404+
405+
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
406+
phydev->supported);
407+
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
408+
phydev->advertising);
409+
410+
/* Auto neg is not supported in fiber mode */
411+
bmcr = phy_read(phydev, MII_BMCR);
412+
if (bmcr < 0)
413+
return bmcr;
414+
415+
if (bmcr & BMCR_ANENABLE) {
416+
err = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
417+
if (err < 0)
418+
return err;
419+
}
420+
phydev->autoneg = AUTONEG_DISABLE;
421+
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
422+
phydev->supported);
423+
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
424+
phydev->advertising);
425+
426+
/* Setup fiber advertisement */
427+
err = phy_modify_changed(phydev, MII_ADVERTISE,
428+
MII_DP83822_FIBER_ADVERTISE,
429+
MII_DP83822_FIBER_ADVERTISE);
430+
431+
if (err < 0)
432+
return err;
433+
434+
if (dp83822->fx_signal_det_low) {
435+
err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
436+
MII_DP83822_GENCFG,
437+
DP83822_SIG_DET_LOW);
438+
if (err)
439+
return err;
440+
}
441+
}
305442
return dp8382x_disable_wol(phydev);
306443
}
307444

@@ -314,13 +451,85 @@ static int dp83822_phy_reset(struct phy_device *phydev)
314451
{
315452
int err;
316453

317-
err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET);
454+
err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET);
318455
if (err < 0)
319456
return err;
320457

321458
return phydev->drv->config_init(phydev);
322459
}
323460

461+
#ifdef CONFIG_OF_MDIO
462+
static int dp83822_of_init(struct phy_device *phydev)
463+
{
464+
struct dp83822_private *dp83822 = phydev->priv;
465+
struct device *dev = &phydev->mdio.dev;
466+
467+
/* Signal detection for the PHY is only enabled if the FX_EN and the
468+
* SD_EN pins are strapped. Signal detection can only enabled if FX_EN
469+
* is strapped otherwise signal detection is disabled for the PHY.
470+
*/
471+
if (dp83822->fx_enabled && dp83822->fx_sd_enable)
472+
dp83822->fx_signal_det_low = device_property_present(dev,
473+
"ti,link-loss-low");
474+
if (!dp83822->fx_enabled)
475+
dp83822->fx_enabled = device_property_present(dev,
476+
"ti,fiber-mode");
477+
478+
return 0;
479+
}
480+
#else
481+
static int dp83822_of_init(struct phy_device *phydev)
482+
{
483+
return 0;
484+
}
485+
#endif /* CONFIG_OF_MDIO */
486+
487+
static int dp83822_read_straps(struct phy_device *phydev)
488+
{
489+
struct dp83822_private *dp83822 = phydev->priv;
490+
int fx_enabled, fx_sd_enable;
491+
int val;
492+
493+
val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1);
494+
if (val < 0)
495+
return val;
496+
497+
fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT;
498+
if (fx_enabled == DP83822_STRAP_MODE2 ||
499+
fx_enabled == DP83822_STRAP_MODE3)
500+
dp83822->fx_enabled = 1;
501+
502+
if (dp83822->fx_enabled) {
503+
fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT;
504+
if (fx_sd_enable == DP83822_STRAP_MODE3 ||
505+
fx_sd_enable == DP83822_STRAP_MODE4)
506+
dp83822->fx_sd_enable = 1;
507+
}
508+
509+
return 0;
510+
}
511+
512+
static int dp83822_probe(struct phy_device *phydev)
513+
{
514+
struct dp83822_private *dp83822;
515+
int ret;
516+
517+
dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822),
518+
GFP_KERNEL);
519+
if (!dp83822)
520+
return -ENOMEM;
521+
522+
phydev->priv = dp83822;
523+
524+
ret = dp83822_read_straps(phydev);
525+
if (ret)
526+
return ret;
527+
528+
dp83822_of_init(phydev);
529+
530+
return 0;
531+
}
532+
324533
static int dp83822_suspend(struct phy_device *phydev)
325534
{
326535
int value;
@@ -352,8 +561,10 @@ static int dp83822_resume(struct phy_device *phydev)
352561
PHY_ID_MATCH_MODEL(_id), \
353562
.name = (_name), \
354563
/* PHY_BASIC_FEATURES */ \
564+
.probe = dp83822_probe, \
355565
.soft_reset = dp83822_phy_reset, \
356566
.config_init = dp83822_config_init, \
567+
.read_status = dp83822_read_status, \
357568
.get_wol = dp83822_get_wol, \
358569
.set_wol = dp83822_set_wol, \
359570
.ack_interrupt = dp83822_ack_interrupt, \

0 commit comments

Comments
 (0)