Loading...
Note: File does not exist in v3.1.
1// SPDX-License-Identifier: GPL-2.0+
2
3#include <linux/phy.h>
4#include <linux/module.h>
5
6#include "qcom.h"
7
8#define AT803X_DEBUG_REG_3C 0x3C
9
10#define AT803X_DEBUG_REG_GREEN 0x3D
11#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
12
13#define MDIO_AZ_DEBUG 0x800D
14
15#define QCA8327_A_PHY_ID 0x004dd033
16#define QCA8327_B_PHY_ID 0x004dd034
17#define QCA8337_PHY_ID 0x004dd036
18#define QCA8K_PHY_ID_MASK 0xffffffff
19
20#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
21
22static struct at803x_hw_stat qca83xx_hw_stats[] = {
23 { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
24 { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
25 { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
26};
27
28struct qca83xx_priv {
29 u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
30};
31
32MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
33MODULE_AUTHOR("Matus Ujhelyi");
34MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
35MODULE_LICENSE("GPL");
36
37static int qca83xx_get_sset_count(struct phy_device *phydev)
38{
39 return ARRAY_SIZE(qca83xx_hw_stats);
40}
41
42static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
43{
44 int i;
45
46 for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
47 strscpy(data + i * ETH_GSTRING_LEN,
48 qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
49 }
50}
51
52static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
53{
54 struct at803x_hw_stat stat = qca83xx_hw_stats[i];
55 struct qca83xx_priv *priv = phydev->priv;
56 int val;
57 u64 ret;
58
59 if (stat.access_type == MMD)
60 val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
61 else
62 val = phy_read(phydev, stat.reg);
63
64 if (val < 0) {
65 ret = U64_MAX;
66 } else {
67 val = val & stat.mask;
68 priv->stats[i] += val;
69 ret = priv->stats[i];
70 }
71
72 return ret;
73}
74
75static void qca83xx_get_stats(struct phy_device *phydev,
76 struct ethtool_stats *stats, u64 *data)
77{
78 int i;
79
80 for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
81 data[i] = qca83xx_get_stat(phydev, i);
82}
83
84static int qca83xx_probe(struct phy_device *phydev)
85{
86 struct device *dev = &phydev->mdio.dev;
87 struct qca83xx_priv *priv;
88
89 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
90 if (!priv)
91 return -ENOMEM;
92
93 phydev->priv = priv;
94
95 return 0;
96}
97
98static int qca83xx_config_init(struct phy_device *phydev)
99{
100 u8 switch_revision;
101
102 switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
103
104 switch (switch_revision) {
105 case 1:
106 /* For 100M waveform */
107 at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
108 /* Turn on Gigabit clock */
109 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
110 break;
111
112 case 2:
113 phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
114 fallthrough;
115 case 4:
116 phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
117 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
118 at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
119 at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
120 break;
121 }
122
123 /* Following original QCA sourcecode set port to prefer master */
124 phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
125
126 return 0;
127}
128
129static int qca8327_config_init(struct phy_device *phydev)
130{
131 /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
132 * Disable on init and enable only with 100m speed following
133 * qca original source code.
134 */
135 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
136 QCA8327_DEBUG_MANU_CTRL_EN, 0);
137
138 return qca83xx_config_init(phydev);
139}
140
141static void qca83xx_link_change_notify(struct phy_device *phydev)
142{
143 /* Set DAC Amplitude adjustment to +6% for 100m on link running */
144 if (phydev->state == PHY_RUNNING) {
145 if (phydev->speed == SPEED_100)
146 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
147 QCA8327_DEBUG_MANU_CTRL_EN,
148 QCA8327_DEBUG_MANU_CTRL_EN);
149 } else {
150 /* Reset DAC Amplitude adjustment */
151 at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
152 QCA8327_DEBUG_MANU_CTRL_EN, 0);
153 }
154}
155
156static int qca83xx_resume(struct phy_device *phydev)
157{
158 int ret, val;
159
160 /* Skip reset if not suspended */
161 if (!phydev->suspended)
162 return 0;
163
164 /* Reinit the port, reset values set by suspend */
165 qca83xx_config_init(phydev);
166
167 /* Reset the port on port resume */
168 phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
169
170 /* On resume from suspend the switch execute a reset and
171 * restart auto-negotiation. Wait for reset to complete.
172 */
173 ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
174 50000, 600000, true);
175 if (ret)
176 return ret;
177
178 usleep_range(1000, 2000);
179
180 return 0;
181}
182
183static int qca83xx_suspend(struct phy_device *phydev)
184{
185 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
186 AT803X_DEBUG_GATE_CLK_IN1000, 0);
187
188 at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
189 AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
190 AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
191
192 return 0;
193}
194
195static int qca8337_suspend(struct phy_device *phydev)
196{
197 /* Only QCA8337 support actual suspend. */
198 genphy_suspend(phydev);
199
200 return qca83xx_suspend(phydev);
201}
202
203static int qca8327_suspend(struct phy_device *phydev)
204{
205 u16 mask = 0;
206
207 /* QCA8327 cause port unreliability when phy suspend
208 * is set.
209 */
210 mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
211 phy_modify(phydev, MII_BMCR, mask, 0);
212
213 return qca83xx_suspend(phydev);
214}
215
216static struct phy_driver qca83xx_driver[] = {
217{
218 /* QCA8337 */
219 .phy_id = QCA8337_PHY_ID,
220 .phy_id_mask = QCA8K_PHY_ID_MASK,
221 .name = "Qualcomm Atheros 8337 internal PHY",
222 /* PHY_GBIT_FEATURES */
223 .probe = qca83xx_probe,
224 .flags = PHY_IS_INTERNAL,
225 .config_init = qca83xx_config_init,
226 .soft_reset = genphy_soft_reset,
227 .get_sset_count = qca83xx_get_sset_count,
228 .get_strings = qca83xx_get_strings,
229 .get_stats = qca83xx_get_stats,
230 .suspend = qca8337_suspend,
231 .resume = qca83xx_resume,
232}, {
233 /* QCA8327-A from switch QCA8327-AL1A */
234 .phy_id = QCA8327_A_PHY_ID,
235 .phy_id_mask = QCA8K_PHY_ID_MASK,
236 .name = "Qualcomm Atheros 8327-A internal PHY",
237 /* PHY_GBIT_FEATURES */
238 .link_change_notify = qca83xx_link_change_notify,
239 .probe = qca83xx_probe,
240 .flags = PHY_IS_INTERNAL,
241 .config_init = qca8327_config_init,
242 .soft_reset = genphy_soft_reset,
243 .get_sset_count = qca83xx_get_sset_count,
244 .get_strings = qca83xx_get_strings,
245 .get_stats = qca83xx_get_stats,
246 .suspend = qca8327_suspend,
247 .resume = qca83xx_resume,
248}, {
249 /* QCA8327-B from switch QCA8327-BL1A */
250 .phy_id = QCA8327_B_PHY_ID,
251 .phy_id_mask = QCA8K_PHY_ID_MASK,
252 .name = "Qualcomm Atheros 8327-B internal PHY",
253 /* PHY_GBIT_FEATURES */
254 .link_change_notify = qca83xx_link_change_notify,
255 .probe = qca83xx_probe,
256 .flags = PHY_IS_INTERNAL,
257 .config_init = qca8327_config_init,
258 .soft_reset = genphy_soft_reset,
259 .get_sset_count = qca83xx_get_sset_count,
260 .get_strings = qca83xx_get_strings,
261 .get_stats = qca83xx_get_stats,
262 .suspend = qca8327_suspend,
263 .resume = qca83xx_resume,
264}, };
265
266module_phy_driver(qca83xx_driver);
267
268static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
269 { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
270 { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
271 { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
272 { }
273};
274
275MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);