xref: /linux/drivers/net/phy/qcom/qca83xx.c (revision 2e45d404)
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 
22 static 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 
28 struct qca83xx_priv {
29 	u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
30 };
31 
32 MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
33 MODULE_AUTHOR("Matus Ujhelyi");
34 MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
35 MODULE_LICENSE("GPL");
36 
qca83xx_get_sset_count(struct phy_device * phydev)37 static int qca83xx_get_sset_count(struct phy_device *phydev)
38 {
39 	return ARRAY_SIZE(qca83xx_hw_stats);
40 }
41 
qca83xx_get_strings(struct phy_device * phydev,u8 * data)42 static 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 
qca83xx_get_stat(struct phy_device * phydev,int i)52 static 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 
qca83xx_get_stats(struct phy_device * phydev,struct ethtool_stats * stats,u64 * data)75 static 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 
qca83xx_probe(struct phy_device * phydev)84 static 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 
qca83xx_config_init(struct phy_device * phydev)98 static 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 
qca8327_config_init(struct phy_device * phydev)129 static 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 
qca83xx_link_change_notify(struct phy_device * phydev)141 static 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 
qca83xx_resume(struct phy_device * phydev)156 static 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 
qca83xx_suspend(struct phy_device * phydev)183 static 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 
qca8337_suspend(struct phy_device * phydev)195 static 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 
qca8327_suspend(struct phy_device * phydev)203 static 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 
216 static 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 
266 module_phy_driver(qca83xx_driver);
267 
268 static 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 
275 MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);
276