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