brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · a05d0df Raw
272 lines · c
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			0x3C9 10#define AT803X_DEBUG_REG_GREEN			0x3D11#define   AT803X_DEBUG_GATE_CLK_IN1000		BIT(6)12 13#define MDIO_AZ_DEBUG				0x800D14 15#define QCA8327_A_PHY_ID			0x004dd03316#define QCA8327_B_PHY_ID			0x004dd03417#define QCA8337_PHY_ID				0x004dd03618 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		strscpy(data + i * ETH_GSTRING_LEN,47			qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);48	}49}50 51static 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	else61		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 74static 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 83static 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 97static 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 128static 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 following132	 * 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 140static 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 155static 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 and170	 * 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 182static 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 194static 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 202static int qca8327_suspend(struct phy_device *phydev)203{204	u16 mask = 0;205 206	/* QCA8327 cause port unreliability when phy suspend207	 * 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 215static 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 262module_phy_driver(qca83xx_driver);263 264static 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 271MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);272