Linux Audio

Check our new training course

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