Skip to content

Commit 613707e

Browse files
committed
Merge branch 'add-ti-dp83td510-support'
Oleksij Rempel says: ==================== add ti dp83td510 support changes v4: - dp83td510: remove unused variables - s/base1/baset1 - s/genphy_c45_baset1_read_master_slave/genphy_c45_pma_baset1_read_master_slave changes v3: - export reusable code snippets and make use of it in the dp83td510 driver changes v2: - rewrite the driver reduce usage of common code and to reduce amount of quirks. - add genphy_c45_baset1_an_config_aneg fix ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 5dd6da2 + 165cd04 commit 613707e

File tree

5 files changed

+286
-27
lines changed

5 files changed

+286
-27
lines changed

drivers/net/phy/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,12 @@ config DP83869_PHY
342342
Currently supports the DP83869 PHY. This PHY supports copper and
343343
fiber connections.
344344

345+
config DP83TD510_PHY
346+
tristate "Texas Instruments DP83TD510 Ethernet 10Base-T1L PHY"
347+
help
348+
Support for the DP83TD510 Ethernet 10Base-T1L PHY. This PHY supports
349+
a 10M single pair Ethernet connection for up to 1000 meter cable.
350+
345351
config VITESSE_PHY
346352
tristate "Vitesse PHYs"
347353
help

drivers/net/phy/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o
5757
obj-$(CONFIG_DP83867_PHY) += dp83867.o
5858
obj-$(CONFIG_DP83869_PHY) += dp83869.o
5959
obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o
60+
obj-$(CONFIG_DP83TD510_PHY) += dp83td510.o
6061
obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
6162
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
6263
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o

drivers/net/phy/dp83td510.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Driver for the Texas Instruments DP83TD510 PHY
3+
* Copyright (c) 2022 Pengutronix, Oleksij Rempel <[email protected]>
4+
*/
5+
6+
#include <linux/bitfield.h>
7+
#include <linux/kernel.h>
8+
#include <linux/module.h>
9+
#include <linux/phy.h>
10+
11+
#define DP83TD510E_PHY_ID 0x20000181
12+
13+
/* MDIO_MMD_VEND2 registers */
14+
#define DP83TD510E_PHY_STS 0x10
15+
#define DP83TD510E_STS_MII_INT BIT(7)
16+
#define DP83TD510E_LINK_STATUS BIT(0)
17+
18+
#define DP83TD510E_GEN_CFG 0x11
19+
#define DP83TD510E_GENCFG_INT_POLARITY BIT(3)
20+
#define DP83TD510E_GENCFG_INT_EN BIT(1)
21+
#define DP83TD510E_GENCFG_INT_OE BIT(0)
22+
23+
#define DP83TD510E_INTERRUPT_REG_1 0x12
24+
#define DP83TD510E_INT1_LINK BIT(13)
25+
#define DP83TD510E_INT1_LINK_EN BIT(5)
26+
27+
#define DP83TD510E_AN_STAT_1 0x60c
28+
#define DP83TD510E_MASTER_SLAVE_RESOL_FAIL BIT(15)
29+
30+
static int dp83td510_config_intr(struct phy_device *phydev)
31+
{
32+
int ret;
33+
34+
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
35+
/* Clear any pending interrupts */
36+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
37+
0x0);
38+
if (ret)
39+
return ret;
40+
41+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
42+
DP83TD510E_INTERRUPT_REG_1,
43+
DP83TD510E_INT1_LINK_EN);
44+
if (ret)
45+
return ret;
46+
47+
ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
48+
DP83TD510E_GEN_CFG,
49+
DP83TD510E_GENCFG_INT_POLARITY |
50+
DP83TD510E_GENCFG_INT_EN |
51+
DP83TD510E_GENCFG_INT_OE);
52+
} else {
53+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
54+
DP83TD510E_INTERRUPT_REG_1, 0x0);
55+
if (ret)
56+
return ret;
57+
58+
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
59+
DP83TD510E_GEN_CFG,
60+
DP83TD510E_GENCFG_INT_EN);
61+
if (ret)
62+
return ret;
63+
64+
/* Clear any pending interrupts */
65+
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
66+
0x0);
67+
}
68+
69+
return ret;
70+
}
71+
72+
static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev)
73+
{
74+
int ret;
75+
76+
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS);
77+
if (ret < 0) {
78+
phy_error(phydev);
79+
return IRQ_NONE;
80+
} else if (!(ret & DP83TD510E_STS_MII_INT)) {
81+
return IRQ_NONE;
82+
}
83+
84+
/* Read the current enabled interrupts */
85+
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1);
86+
if (ret < 0) {
87+
phy_error(phydev);
88+
return IRQ_NONE;
89+
} else if (!(ret & DP83TD510E_INT1_LINK_EN) ||
90+
!(ret & DP83TD510E_INT1_LINK)) {
91+
return IRQ_NONE;
92+
}
93+
94+
phy_trigger_machine(phydev);
95+
96+
return IRQ_HANDLED;
97+
}
98+
99+
static int dp83td510_read_status(struct phy_device *phydev)
100+
{
101+
u16 phy_sts;
102+
int ret;
103+
104+
phydev->speed = SPEED_UNKNOWN;
105+
phydev->duplex = DUPLEX_UNKNOWN;
106+
phydev->pause = 0;
107+
phydev->asym_pause = 0;
108+
linkmode_zero(phydev->lp_advertising);
109+
110+
phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);
111+
112+
phydev->link = !!(phy_sts & DP83TD510E_LINK_STATUS);
113+
if (phydev->link) {
114+
/* This PHY supports only one link mode: 10BaseT1L_Full */
115+
phydev->duplex = DUPLEX_FULL;
116+
phydev->speed = SPEED_10;
117+
118+
if (phydev->autoneg == AUTONEG_ENABLE) {
119+
ret = genphy_c45_read_lpa(phydev);
120+
if (ret)
121+
return ret;
122+
123+
phy_resolve_aneg_linkmode(phydev);
124+
}
125+
}
126+
127+
if (phydev->autoneg == AUTONEG_ENABLE) {
128+
ret = genphy_c45_baset1_read_status(phydev);
129+
if (ret < 0)
130+
return ret;
131+
132+
ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
133+
DP83TD510E_AN_STAT_1);
134+
if (ret < 0)
135+
return ret;
136+
137+
if (ret & DP83TD510E_MASTER_SLAVE_RESOL_FAIL)
138+
phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;
139+
} else {
140+
return genphy_c45_pma_baset1_read_master_slave(phydev);
141+
}
142+
143+
return 0;
144+
}
145+
146+
static int dp83td510_config_aneg(struct phy_device *phydev)
147+
{
148+
bool changed = false;
149+
int ret;
150+
151+
ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
152+
if (ret < 0)
153+
return ret;
154+
155+
if (phydev->autoneg == AUTONEG_DISABLE)
156+
return genphy_c45_an_disable_aneg(phydev);
157+
158+
ret = genphy_c45_an_config_aneg(phydev);
159+
if (ret < 0)
160+
return ret;
161+
if (ret > 0)
162+
changed = true;
163+
164+
return genphy_c45_check_and_restart_aneg(phydev, changed);
165+
}
166+
167+
static int dp83td510_get_features(struct phy_device *phydev)
168+
{
169+
/* This PHY can't respond on MDIO bus if no RMII clock is enabled.
170+
* In case RMII mode is used (most meaningful mode for this PHY) and
171+
* the PHY do not have own XTAL, and CLK providing MAC is not probed,
172+
* we won't be able to read all needed ability registers.
173+
* So provide it manually.
174+
*/
175+
176+
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
177+
linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
178+
linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
179+
linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
180+
phydev->supported);
181+
182+
return 0;
183+
}
184+
185+
static struct phy_driver dp83td510_driver[] = {
186+
{
187+
PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID),
188+
.name = "TI DP83TD510E",
189+
190+
.config_aneg = dp83td510_config_aneg,
191+
.read_status = dp83td510_read_status,
192+
.get_features = dp83td510_get_features,
193+
.config_intr = dp83td510_config_intr,
194+
.handle_interrupt = dp83td510_handle_interrupt,
195+
196+
.suspend = genphy_suspend,
197+
.resume = genphy_resume,
198+
} };
199+
module_phy_driver(dp83td510_driver);
200+
201+
static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
202+
{ PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
203+
{ }
204+
};
205+
MODULE_DEVICE_TABLE(mdio, dp83td510_tbl);
206+
207+
MODULE_DESCRIPTION("Texas Instruments DP83TD510E PHY driver");
208+
MODULE_AUTHOR("Oleksij Rempel <[email protected]>");
209+
MODULE_LICENSE("GPL v2");

drivers/net/phy/phy-c45.c

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,36 @@ int genphy_c45_pma_suspend(struct phy_device *phydev)
7070
}
7171
EXPORT_SYMBOL_GPL(genphy_c45_pma_suspend);
7272

73+
/**
74+
* genphy_c45_pma_baset1_setup_master_slave - configures forced master/slave
75+
* role of BaseT1 devices.
76+
* @phydev: target phy_device struct
77+
*/
78+
int genphy_c45_pma_baset1_setup_master_slave(struct phy_device *phydev)
79+
{
80+
int ctl = 0;
81+
82+
switch (phydev->master_slave_set) {
83+
case MASTER_SLAVE_CFG_MASTER_PREFERRED:
84+
case MASTER_SLAVE_CFG_MASTER_FORCE:
85+
ctl = MDIO_PMA_PMD_BT1_CTRL_CFG_MST;
86+
break;
87+
case MASTER_SLAVE_CFG_SLAVE_FORCE:
88+
case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
89+
break;
90+
case MASTER_SLAVE_CFG_UNKNOWN:
91+
case MASTER_SLAVE_CFG_UNSUPPORTED:
92+
return 0;
93+
default:
94+
phydev_warn(phydev, "Unsupported Master/Slave mode\n");
95+
return -EOPNOTSUPP;
96+
}
97+
98+
return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,
99+
MDIO_PMA_PMD_BT1_CTRL_CFG_MST, ctl);
100+
}
101+
EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_setup_master_slave);
102+
73103
/**
74104
* genphy_c45_pma_setup_forced - configures a forced speed
75105
* @phydev: target phy_device struct
@@ -141,25 +171,7 @@ int genphy_c45_pma_setup_forced(struct phy_device *phydev)
141171
return ret;
142172

143173
if (genphy_c45_baset1_able(phydev)) {
144-
int ctl = 0;
145-
146-
switch (phydev->master_slave_set) {
147-
case MASTER_SLAVE_CFG_MASTER_PREFERRED:
148-
case MASTER_SLAVE_CFG_MASTER_FORCE:
149-
ctl = MDIO_PMA_PMD_BT1_CTRL_CFG_MST;
150-
break;
151-
case MASTER_SLAVE_CFG_SLAVE_FORCE:
152-
case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
153-
case MASTER_SLAVE_CFG_UNKNOWN:
154-
case MASTER_SLAVE_CFG_UNSUPPORTED:
155-
break;
156-
default:
157-
phydev_warn(phydev, "Unsupported Master/Slave mode\n");
158-
return -EOPNOTSUPP;
159-
}
160-
161-
ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,
162-
MDIO_PMA_PMD_BT1_CTRL_CFG_MST, ctl);
174+
ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
163175
if (ret < 0)
164176
return ret;
165177
}
@@ -191,8 +203,12 @@ static int genphy_c45_baset1_an_config_aneg(struct phy_device *phydev)
191203
case MASTER_SLAVE_CFG_MASTER_PREFERRED:
192204
case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
193205
break;
206+
case MASTER_SLAVE_CFG_UNKNOWN:
207+
case MASTER_SLAVE_CFG_UNSUPPORTED:
208+
return 0;
194209
default:
195-
break;
210+
phydev_warn(phydev, "Unsupported Master/Slave mode\n");
211+
return -EOPNOTSUPP;
196212
}
197213

198214
switch (phydev->master_slave_set) {
@@ -534,6 +550,34 @@ int genphy_c45_read_lpa(struct phy_device *phydev)
534550
}
535551
EXPORT_SYMBOL_GPL(genphy_c45_read_lpa);
536552

553+
/**
554+
* genphy_c45_pma_baset1_read_master_slave - read forced master/slave
555+
* configuration
556+
* @phydev: target phy_device struct
557+
*/
558+
int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev)
559+
{
560+
int val;
561+
562+
phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
563+
phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
564+
565+
val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL);
566+
if (val < 0)
567+
return val;
568+
569+
if (val & MDIO_PMA_PMD_BT1_CTRL_CFG_MST) {
570+
phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
571+
phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
572+
} else {
573+
phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
574+
phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
575+
}
576+
577+
return 0;
578+
}
579+
EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_master_slave);
580+
537581
/**
538582
* genphy_c45_read_pma - read link speed etc from PMA
539583
* @phydev: target phy_device struct
@@ -575,14 +619,9 @@ int genphy_c45_read_pma(struct phy_device *phydev)
575619
phydev->duplex = DUPLEX_FULL;
576620

577621
if (genphy_c45_baset1_able(phydev)) {
578-
val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL);
622+
val = genphy_c45_pma_baset1_read_master_slave(phydev);
579623
if (val < 0)
580624
return val;
581-
582-
if (MDIO_PMA_PMD_BT1_CTRL_CFG_MST)
583-
phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
584-
else
585-
phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
586625
}
587626

588627
return 0;
@@ -746,7 +785,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities);
746785
* is forced or not, it is read from BASE-T1 AN advertisement
747786
* register 7.514.
748787
*/
749-
static int genphy_c45_baset1_read_status(struct phy_device *phydev)
788+
int genphy_c45_baset1_read_status(struct phy_device *phydev)
750789
{
751790
int ret;
752791
int cfg;
@@ -776,6 +815,7 @@ static int genphy_c45_baset1_read_status(struct phy_device *phydev)
776815

777816
return 0;
778817
}
818+
EXPORT_SYMBOL_GPL(genphy_c45_baset1_read_status);
779819

780820
/**
781821
* genphy_c45_read_status - read PHY status

include/linux/phy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,11 +1614,14 @@ int genphy_c45_read_link(struct phy_device *phydev);
16141614
int genphy_c45_read_lpa(struct phy_device *phydev);
16151615
int genphy_c45_read_pma(struct phy_device *phydev);
16161616
int genphy_c45_pma_setup_forced(struct phy_device *phydev);
1617+
int genphy_c45_pma_baset1_setup_master_slave(struct phy_device *phydev);
16171618
int genphy_c45_an_config_aneg(struct phy_device *phydev);
16181619
int genphy_c45_an_disable_aneg(struct phy_device *phydev);
16191620
int genphy_c45_read_mdix(struct phy_device *phydev);
16201621
int genphy_c45_pma_read_abilities(struct phy_device *phydev);
1622+
int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev);
16211623
int genphy_c45_read_status(struct phy_device *phydev);
1624+
int genphy_c45_baset1_read_status(struct phy_device *phydev);
16221625
int genphy_c45_config_aneg(struct phy_device *phydev);
16231626
int genphy_c45_loopback(struct phy_device *phydev, bool enable);
16241627
int genphy_c45_pma_resume(struct phy_device *phydev);

0 commit comments

Comments
 (0)