| From dbe1079d0d2698e54884986a4a5d156ceef654cb Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 11 Jul 2021 18:38:15 +0200 |
| Subject: net: phy: marvell10g: fix differentiation of 88X3310 from 88X3340 |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Marek Behún <kabel@kernel.org> |
| |
| [ Upstream commit a5de4be0aaaa66a2fa98e8a33bdbed3bd0682804 ] |
| |
| It seems that we cannot differentiate 88X3310 from 88X3340 by simply |
| looking at bit 3 of revision ID. This only works on revisions A0 and A1. |
| On revision B0, this bit is always 1. |
| |
| Instead use the 3.d00d register for differentiation, since this register |
| contains information about number of ports on the device. |
| |
| Fixes: 9885d016ffa9 ("net: phy: marvell10g: add separate structure for 88X3340") |
| Signed-off-by: Marek Behún <kabel@kernel.org> |
| Reported-by: Matteo Croce <mcroce@linux.microsoft.com> |
| Tested-by: Matteo Croce <mcroce@microsoft.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/phy/marvell10g.c | 40 +++++++++++++++++++++++++++++++----- |
| include/linux/marvell_phy.h | 6 +----- |
| 2 files changed, 36 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c |
| index bbbc6ac8fa82..53a433442803 100644 |
| --- a/drivers/net/phy/marvell10g.c |
| +++ b/drivers/net/phy/marvell10g.c |
| @@ -78,6 +78,11 @@ enum { |
| /* Temperature read register (88E2110 only) */ |
| MV_PCS_TEMP = 0x8042, |
| |
| + /* Number of ports on the device */ |
| + MV_PCS_PORT_INFO = 0xd00d, |
| + MV_PCS_PORT_INFO_NPORTS_MASK = 0x0380, |
| + MV_PCS_PORT_INFO_NPORTS_SHIFT = 7, |
| + |
| /* These registers appear at 0x800X and 0xa00X - the 0xa00X control |
| * registers appear to set themselves to the 0x800X when AN is |
| * restarted, but status registers appear readable from either. |
| @@ -966,6 +971,30 @@ static const struct mv3310_chip mv2111_type = { |
| #endif |
| }; |
| |
| +static int mv3310_get_number_of_ports(struct phy_device *phydev) |
| +{ |
| + int ret; |
| + |
| + ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PORT_INFO); |
| + if (ret < 0) |
| + return ret; |
| + |
| + ret &= MV_PCS_PORT_INFO_NPORTS_MASK; |
| + ret >>= MV_PCS_PORT_INFO_NPORTS_SHIFT; |
| + |
| + return ret + 1; |
| +} |
| + |
| +static int mv3310_match_phy_device(struct phy_device *phydev) |
| +{ |
| + return mv3310_get_number_of_ports(phydev) == 1; |
| +} |
| + |
| +static int mv3340_match_phy_device(struct phy_device *phydev) |
| +{ |
| + return mv3310_get_number_of_ports(phydev) == 4; |
| +} |
| + |
| static int mv211x_match_phy_device(struct phy_device *phydev, bool has_5g) |
| { |
| int val; |
| @@ -994,7 +1023,8 @@ static int mv2111_match_phy_device(struct phy_device *phydev) |
| static struct phy_driver mv3310_drivers[] = { |
| { |
| .phy_id = MARVELL_PHY_ID_88X3310, |
| - .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, |
| + .phy_id_mask = MARVELL_PHY_ID_MASK, |
| + .match_phy_device = mv3310_match_phy_device, |
| .name = "mv88x3310", |
| .driver_data = &mv3310_type, |
| .get_features = mv3310_get_features, |
| @@ -1011,8 +1041,9 @@ static struct phy_driver mv3310_drivers[] = { |
| .set_loopback = genphy_c45_loopback, |
| }, |
| { |
| - .phy_id = MARVELL_PHY_ID_88X3340, |
| - .phy_id_mask = MARVELL_PHY_ID_88X33X0_MASK, |
| + .phy_id = MARVELL_PHY_ID_88X3310, |
| + .phy_id_mask = MARVELL_PHY_ID_MASK, |
| + .match_phy_device = mv3340_match_phy_device, |
| .name = "mv88x3340", |
| .driver_data = &mv3340_type, |
| .get_features = mv3310_get_features, |
| @@ -1069,8 +1100,7 @@ static struct phy_driver mv3310_drivers[] = { |
| module_phy_driver(mv3310_drivers); |
| |
| static struct mdio_device_id __maybe_unused mv3310_tbl[] = { |
| - { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_88X33X0_MASK }, |
| - { MARVELL_PHY_ID_88X3340, MARVELL_PHY_ID_88X33X0_MASK }, |
| + { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK }, |
| { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK }, |
| { }, |
| }; |
| diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h |
| index acee44b9db26..0f06c2287b52 100644 |
| --- a/include/linux/marvell_phy.h |
| +++ b/include/linux/marvell_phy.h |
| @@ -22,14 +22,10 @@ |
| #define MARVELL_PHY_ID_88E1545 0x01410ea0 |
| #define MARVELL_PHY_ID_88E1548P 0x01410ec0 |
| #define MARVELL_PHY_ID_88E3016 0x01410e60 |
| +#define MARVELL_PHY_ID_88X3310 0x002b09a0 |
| #define MARVELL_PHY_ID_88E2110 0x002b09b0 |
| #define MARVELL_PHY_ID_88X2222 0x01410f10 |
| |
| -/* PHY IDs and mask for Alaska 10G PHYs */ |
| -#define MARVELL_PHY_ID_88X33X0_MASK 0xfffffff8 |
| -#define MARVELL_PHY_ID_88X3310 0x002b09a0 |
| -#define MARVELL_PHY_ID_88X3340 0x002b09a8 |
| - |
| /* Marvel 88E1111 in Finisar SFP module with modified PHY ID */ |
| #define MARVELL_PHY_ID_88E1111_FINISAR 0x01ff0cc0 |
| |
| -- |
| 2.30.2 |
| |