Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee825e8b authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'phy-aquantia-improvements'



Heiner Kallweit says:

====================
net: phy: aquantia: number of improvements

This patch series is based on work from Andrew. I adjusted and added
certain parts. The series improves few aspects of driver, no functional
change intended.

v2:
- add my SoB to patch 1
- leave kernel.h in in patch 2
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9fb20801 278f6b67
Loading
Loading
Loading
Loading
+110 −67
Original line number Original line Diff line number Diff line
@@ -10,10 +10,7 @@
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/phy.h>
#include <linux/mdio.h>


#define PHY_ID_AQ1202	0x03a1b445
#define PHY_ID_AQ1202	0x03a1b445
#define PHY_ID_AQ2104	0x03a1b460
#define PHY_ID_AQ2104	0x03a1b460
@@ -22,7 +19,49 @@
#define PHY_ID_AQR107	0x03a1b4e0
#define PHY_ID_AQR107	0x03a1b4e0
#define PHY_ID_AQR405	0x03a1b4b0
#define PHY_ID_AQR405	0x03a1b4b0


static int aquantia_config_aneg(struct phy_device *phydev)
#define MDIO_AN_TX_VEND_STATUS1			0xc800
#define MDIO_AN_TX_VEND_STATUS1_10BASET		(0x0 << 1)
#define MDIO_AN_TX_VEND_STATUS1_100BASETX	(0x1 << 1)
#define MDIO_AN_TX_VEND_STATUS1_1000BASET	(0x2 << 1)
#define MDIO_AN_TX_VEND_STATUS1_10GBASET	(0x3 << 1)
#define MDIO_AN_TX_VEND_STATUS1_2500BASET	(0x4 << 1)
#define MDIO_AN_TX_VEND_STATUS1_5000BASET	(0x5 << 1)
#define MDIO_AN_TX_VEND_STATUS1_RATE_MASK	(0x7 << 1)
#define MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX	BIT(0)

#define MDIO_AN_TX_VEND_INT_STATUS2		0xcc01

#define MDIO_AN_TX_VEND_INT_MASK2		0xd401
#define MDIO_AN_TX_VEND_INT_MASK2_LINK		BIT(0)

/* Vendor specific 1, MDIO_MMD_VEND1 */
#define VEND1_GLOBAL_INT_STD_STATUS		0xfc00
#define VEND1_GLOBAL_INT_VEND_STATUS		0xfc01

#define VEND1_GLOBAL_INT_STD_MASK		0xff00
#define VEND1_GLOBAL_INT_STD_MASK_PMA1		BIT(15)
#define VEND1_GLOBAL_INT_STD_MASK_PMA2		BIT(14)
#define VEND1_GLOBAL_INT_STD_MASK_PCS1		BIT(13)
#define VEND1_GLOBAL_INT_STD_MASK_PCS2		BIT(12)
#define VEND1_GLOBAL_INT_STD_MASK_PCS3		BIT(11)
#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1	BIT(10)
#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2	BIT(9)
#define VEND1_GLOBAL_INT_STD_MASK_AN1		BIT(8)
#define VEND1_GLOBAL_INT_STD_MASK_AN2		BIT(7)
#define VEND1_GLOBAL_INT_STD_MASK_GBE		BIT(6)
#define VEND1_GLOBAL_INT_STD_MASK_ALL		BIT(0)

#define VEND1_GLOBAL_INT_VEND_MASK		0xff01
#define VEND1_GLOBAL_INT_VEND_MASK_PMA		BIT(15)
#define VEND1_GLOBAL_INT_VEND_MASK_PCS		BIT(14)
#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS	BIT(13)
#define VEND1_GLOBAL_INT_VEND_MASK_AN		BIT(12)
#define VEND1_GLOBAL_INT_VEND_MASK_GBE		BIT(11)
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1	BIT(2)
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2	BIT(1)
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3	BIT(0)

static int aqr_config_aneg(struct phy_device *phydev)
{
{
	linkmode_copy(phydev->supported, phy_10gbit_features);
	linkmode_copy(phydev->supported, phy_10gbit_features);
	linkmode_copy(phydev->advertising, phydev->supported);
	linkmode_copy(phydev->advertising, phydev->supported);
@@ -30,44 +69,55 @@ static int aquantia_config_aneg(struct phy_device *phydev)
	return 0;
	return 0;
}
}


static int aquantia_config_intr(struct phy_device *phydev)
static int aqr_config_intr(struct phy_device *phydev)
{
{
	int err;
	int err;


	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1);
		err = phy_write_mmd(phydev, MDIO_MMD_AN,
				    MDIO_AN_TX_VEND_INT_MASK2,
				    MDIO_AN_TX_VEND_INT_MASK2_LINK);
		if (err < 0)
		if (err < 0)
			return err;
			return err;


		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1);
		err = phy_write_mmd(phydev, MDIO_MMD_VEND1,
				    VEND1_GLOBAL_INT_STD_MASK,
				    VEND1_GLOBAL_INT_STD_MASK_ALL);
		if (err < 0)
		if (err < 0)
			return err;
			return err;


		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001);
		err = phy_write_mmd(phydev, MDIO_MMD_VEND1,
				    VEND1_GLOBAL_INT_VEND_MASK,
				    VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 |
				    VEND1_GLOBAL_INT_VEND_MASK_AN);
	} else {
	} else {
		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0);
		err = phy_write_mmd(phydev, MDIO_MMD_AN,
				    MDIO_AN_TX_VEND_INT_MASK2, 0);
		if (err < 0)
		if (err < 0)
			return err;
			return err;


		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0);
		err = phy_write_mmd(phydev, MDIO_MMD_VEND1,
				    VEND1_GLOBAL_INT_STD_MASK, 0);
		if (err < 0)
		if (err < 0)
			return err;
			return err;


		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0);
		err = phy_write_mmd(phydev, MDIO_MMD_VEND1,
				    VEND1_GLOBAL_INT_VEND_MASK, 0);
	}
	}


	return err;
	return err;
}
}


static int aquantia_ack_interrupt(struct phy_device *phydev)
static int aqr_ack_interrupt(struct phy_device *phydev)
{
{
	int reg;
	int reg;


	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01);
	reg = phy_read_mmd(phydev, MDIO_MMD_AN,
			   MDIO_AN_TX_VEND_INT_STATUS2);
	return (reg < 0) ? reg : 0;
	return (reg < 0) ? reg : 0;
}
}


static int aquantia_read_status(struct phy_device *phydev)
static int aqr_read_status(struct phy_device *phydev)
{
{
	int reg;
	int reg;


@@ -78,21 +128,20 @@ static int aquantia_read_status(struct phy_device *phydev)
	else
	else
		phydev->link = 0;
		phydev->link = 0;


	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
	mdelay(10);
	mdelay(10);
	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);


	switch (reg) {
	switch (reg & MDIO_AN_TX_VEND_STATUS1_RATE_MASK) {
	case 0x9:
	case MDIO_AN_TX_VEND_STATUS1_2500BASET:
		phydev->speed = SPEED_2500;
		phydev->speed = SPEED_2500;
		break;
		break;
	case 0x5:
	case MDIO_AN_TX_VEND_STATUS1_1000BASET:
		phydev->speed = SPEED_1000;
		phydev->speed = SPEED_1000;
		break;
		break;
	case 0x3:
	case MDIO_AN_TX_VEND_STATUS1_100BASETX:
		phydev->speed = SPEED_100;
		phydev->speed = SPEED_100;
		break;
		break;
	case 0x7:
	default:
	default:
		phydev->speed = SPEED_10000;
		phydev->speed = SPEED_10000;
		break;
		break;
@@ -102,88 +151,82 @@ static int aquantia_read_status(struct phy_device *phydev)
	return 0;
	return 0;
}
}


static struct phy_driver aquantia_driver[] = {
static struct phy_driver aqr_driver[] = {
{
{
	.phy_id		= PHY_ID_AQ1202,
	PHY_ID_MATCH_MODEL(PHY_ID_AQ1202),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQ1202",
	.name		= "Aquantia AQ1202",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
{
{
	.phy_id		= PHY_ID_AQ2104,
	PHY_ID_MATCH_MODEL(PHY_ID_AQ2104),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQ2104",
	.name		= "Aquantia AQ2104",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
{
{
	.phy_id		= PHY_ID_AQR105,
	PHY_ID_MATCH_MODEL(PHY_ID_AQR105),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQR105",
	.name		= "Aquantia AQR105",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
{
{
	.phy_id		= PHY_ID_AQR106,
	PHY_ID_MATCH_MODEL(PHY_ID_AQR106),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQR106",
	.name		= "Aquantia AQR106",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
{
{
	.phy_id		= PHY_ID_AQR107,
	PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQR107",
	.name		= "Aquantia AQR107",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
{
{
	.phy_id		= PHY_ID_AQR405,
	PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
	.phy_id_mask	= 0xfffffff0,
	.name		= "Aquantia AQR405",
	.name		= "Aquantia AQR405",
	.features	= PHY_10GBIT_FULL_FEATURES,
	.features	= PHY_10GBIT_FULL_FEATURES,
	.aneg_done	= genphy_c45_aneg_done,
	.aneg_done	= genphy_c45_aneg_done,
	.config_aneg    = aquantia_config_aneg,
	.config_aneg    = aqr_config_aneg,
	.config_intr	= aquantia_config_intr,
	.config_intr	= aqr_config_intr,
	.ack_interrupt	= aquantia_ack_interrupt,
	.ack_interrupt	= aqr_ack_interrupt,
	.read_status	= aquantia_read_status,
	.read_status	= aqr_read_status,
},
},
};
};


module_phy_driver(aquantia_driver);
module_phy_driver(aqr_driver);


static struct mdio_device_id __maybe_unused aquantia_tbl[] = {
static struct mdio_device_id __maybe_unused aqr_tbl[] = {
	{ PHY_ID_AQ1202, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQ1202) },
	{ PHY_ID_AQ2104, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQ2104) },
	{ PHY_ID_AQR105, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
	{ PHY_ID_AQR106, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
	{ PHY_ID_AQR107, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
	{ PHY_ID_AQR405, 0xfffffff0 },
	{ PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
	{ }
	{ }
};
};


MODULE_DEVICE_TABLE(mdio, aquantia_tbl);
MODULE_DEVICE_TABLE(mdio, aqr_tbl);


MODULE_DESCRIPTION("Aquantia PHY driver");
MODULE_DESCRIPTION("Aquantia PHY driver");
MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");
MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");