1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Driver for the Texas Instruments DP83TG720 PHY |
3 | * Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> |
4 | */ |
5 | #include <linux/bitfield.h> |
6 | #include <linux/kernel.h> |
7 | #include <linux/module.h> |
8 | #include <linux/phy.h> |
9 | |
10 | #define DP83TG720S_PHY_ID 0x2000a284 |
11 | |
12 | /* MDIO_MMD_VEND2 registers */ |
13 | #define DP83TG720S_MII_REG_10 0x10 |
14 | #define DP83TG720S_STS_MII_INT BIT(7) |
15 | #define DP83TG720S_LINK_STATUS BIT(0) |
16 | |
17 | #define DP83TG720S_PHY_RESET 0x1f |
18 | #define DP83TG720S_HW_RESET BIT(15) |
19 | |
20 | #define DP83TG720S_RGMII_DELAY_CTRL 0x602 |
21 | /* In RGMII mode, Enable or disable the internal delay for RXD */ |
22 | #define DP83TG720S_RGMII_RX_CLK_SEL BIT(1) |
23 | /* In RGMII mode, Enable or disable the internal delay for TXD */ |
24 | #define DP83TG720S_RGMII_TX_CLK_SEL BIT(0) |
25 | |
26 | #define DP83TG720S_SQI_REG_1 0x871 |
27 | #define DP83TG720S_SQI_OUT_WORST GENMASK(7, 5) |
28 | #define DP83TG720S_SQI_OUT GENMASK(3, 1) |
29 | |
30 | #define DP83TG720_SQI_MAX 7 |
31 | |
32 | static int dp83tg720_config_aneg(struct phy_device *phydev) |
33 | { |
34 | /* Autoneg is not supported and this PHY supports only one speed. |
35 | * We need to care only about master/slave configuration if it was |
36 | * changed by user. |
37 | */ |
38 | return genphy_c45_pma_baset1_setup_master_slave(phydev); |
39 | } |
40 | |
41 | static int dp83tg720_read_status(struct phy_device *phydev) |
42 | { |
43 | u16 phy_sts; |
44 | int ret; |
45 | |
46 | phydev->pause = 0; |
47 | phydev->asym_pause = 0; |
48 | |
49 | /* Most of Clause 45 registers are not present, so we can't use |
50 | * genphy_c45_read_status() here. |
51 | */ |
52 | phy_sts = phy_read(phydev, DP83TG720S_MII_REG_10); |
53 | phydev->link = !!(phy_sts & DP83TG720S_LINK_STATUS); |
54 | if (!phydev->link) { |
55 | /* According to the "DP83TC81x, DP83TG72x Software |
56 | * Implementation Guide", the PHY needs to be reset after a |
57 | * link loss or if no link is created after at least 100ms. |
58 | * |
59 | * Currently we are polling with the PHY_STATE_TIME (1000ms) |
60 | * interval, which is still enough for not automotive use cases. |
61 | */ |
62 | ret = phy_init_hw(phydev); |
63 | if (ret) |
64 | return ret; |
65 | |
66 | /* After HW reset we need to restore master/slave configuration. |
67 | */ |
68 | ret = dp83tg720_config_aneg(phydev); |
69 | if (ret) |
70 | return ret; |
71 | |
72 | phydev->speed = SPEED_UNKNOWN; |
73 | phydev->duplex = DUPLEX_UNKNOWN; |
74 | } else { |
75 | /* PMA/PMD control 1 register (Register 1.0) is present, but it |
76 | * doesn't contain the link speed information. |
77 | * So genphy_c45_read_pma() can't be used here. |
78 | */ |
79 | ret = genphy_c45_pma_baset1_read_master_slave(phydev); |
80 | if (ret) |
81 | return ret; |
82 | |
83 | phydev->duplex = DUPLEX_FULL; |
84 | phydev->speed = SPEED_1000; |
85 | } |
86 | |
87 | return 0; |
88 | } |
89 | |
90 | static int dp83tg720_get_sqi(struct phy_device *phydev) |
91 | { |
92 | int ret; |
93 | |
94 | if (!phydev->link) |
95 | return 0; |
96 | |
97 | ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_SQI_REG_1); |
98 | if (ret < 0) |
99 | return ret; |
100 | |
101 | return FIELD_GET(DP83TG720S_SQI_OUT, ret); |
102 | } |
103 | |
104 | static int dp83tg720_get_sqi_max(struct phy_device *phydev) |
105 | { |
106 | return DP83TG720_SQI_MAX; |
107 | } |
108 | |
109 | static int dp83tg720_config_rgmii_delay(struct phy_device *phydev) |
110 | { |
111 | u16 rgmii_delay_mask; |
112 | u16 rgmii_delay = 0; |
113 | |
114 | switch (phydev->interface) { |
115 | case PHY_INTERFACE_MODE_RGMII: |
116 | rgmii_delay = 0; |
117 | break; |
118 | case PHY_INTERFACE_MODE_RGMII_ID: |
119 | rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL | |
120 | DP83TG720S_RGMII_TX_CLK_SEL; |
121 | break; |
122 | case PHY_INTERFACE_MODE_RGMII_RXID: |
123 | rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL; |
124 | break; |
125 | case PHY_INTERFACE_MODE_RGMII_TXID: |
126 | rgmii_delay = DP83TG720S_RGMII_TX_CLK_SEL; |
127 | break; |
128 | default: |
129 | return 0; |
130 | } |
131 | |
132 | rgmii_delay_mask = DP83TG720S_RGMII_RX_CLK_SEL | |
133 | DP83TG720S_RGMII_TX_CLK_SEL; |
134 | |
135 | return phy_modify_mmd(phydev, MDIO_MMD_VEND2, |
136 | DP83TG720S_RGMII_DELAY_CTRL, mask: rgmii_delay_mask, |
137 | set: rgmii_delay); |
138 | } |
139 | |
140 | static int dp83tg720_config_init(struct phy_device *phydev) |
141 | { |
142 | int ret; |
143 | |
144 | /* Software Restart is not enough to recover from a link failure. |
145 | * Using Hardware Reset instead. |
146 | */ |
147 | ret = phy_write(phydev, DP83TG720S_PHY_RESET, DP83TG720S_HW_RESET); |
148 | if (ret) |
149 | return ret; |
150 | |
151 | /* Wait until MDC can be used again. |
152 | * The wait value of one 1ms is documented in "DP83TG720S-Q1 1000BASE-T1 |
153 | * Automotive Ethernet PHY with SGMII and RGMII" datasheet. |
154 | */ |
155 | usleep_range(min: 1000, max: 2000); |
156 | |
157 | if (phy_interface_is_rgmii(phydev)) |
158 | return dp83tg720_config_rgmii_delay(phydev); |
159 | |
160 | return 0; |
161 | } |
162 | |
163 | static struct phy_driver dp83tg720_driver[] = { |
164 | { |
165 | PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID), |
166 | .name = "TI DP83TG720S" , |
167 | |
168 | .config_aneg = dp83tg720_config_aneg, |
169 | .read_status = dp83tg720_read_status, |
170 | .get_features = genphy_c45_pma_read_ext_abilities, |
171 | .config_init = dp83tg720_config_init, |
172 | .get_sqi = dp83tg720_get_sqi, |
173 | .get_sqi_max = dp83tg720_get_sqi_max, |
174 | |
175 | .suspend = genphy_suspend, |
176 | .resume = genphy_resume, |
177 | } }; |
178 | module_phy_driver(dp83tg720_driver); |
179 | |
180 | static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = { |
181 | { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) }, |
182 | { } |
183 | }; |
184 | MODULE_DEVICE_TABLE(mdio, dp83tg720_tbl); |
185 | |
186 | MODULE_DESCRIPTION("Texas Instruments DP83TG720S PHY driver" ); |
187 | MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>" ); |
188 | MODULE_LICENSE("GPL" ); |
189 | |