mirror of https://gitee.com/openkylin/linux.git
net: pcs: xpcs: add support for NXP SJA1105
The NXP SJA1105 DSA switch integrates a Synopsys SGMII XPCS on port 4. The generic code works fine, except there is an integration issue which needs to be dealt with: in this switch, the XPCS is integrated with a PMA that has the TX lane polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain normal non-inverted behavior, the TX lane polarity must be inverted in the PCS, via the DIGITAL_CONTROL_2 register. We introduce a pma_config() method in xpcs_compat which is called by the phylink_pcs_config() implementation. Also, the NXP SJA1105 returns all zeroes in the PHY ID registers 2 and 3. We need to hack up an ad-hoc PHY ID (OUI is zero, device ID is 1) in order for the XPCS driver to recognize it. This PHY ID is added to the public include/linux/pcs/pcs-xpcs.h for that reason (for the sja1105 driver to be able to use it in a later patch). Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
36641b045c
commit
dd0721ea4c
|
@ -13203,6 +13203,7 @@ M: Vladimir Oltean <olteanv@gmail.com>
|
|||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/dsa/sja1105
|
||||
F: drivers/net/pcs/pcs-xpcs-nxp.c
|
||||
|
||||
NXP TDA998X DRM DRIVER
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Makefile for Linux PCS drivers
|
||||
|
||||
obj-$(CONFIG_PCS_XPCS) += pcs-xpcs.o
|
||||
pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
|
||||
|
||||
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
|
||||
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright 2021 NXP Semiconductors
|
||||
*/
|
||||
#include <linux/pcs/pcs-xpcs.h>
|
||||
#include "pcs-xpcs.h"
|
||||
|
||||
/* In NXP SJA1105, the PCS is integrated with a PMA that has the TX lane
|
||||
* polarity inverted by default (PLUS is MINUS, MINUS is PLUS). To obtain
|
||||
* normal non-inverted behavior, the TX lane polarity must be inverted in the
|
||||
* PCS, via the DIGITAL_CONTROL_2 register.
|
||||
*/
|
||||
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)
|
||||
{
|
||||
return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,
|
||||
DW_VR_MII_DIG_CTRL2_TX_POL_INV);
|
||||
}
|
|
@ -117,6 +117,7 @@ struct xpcs_compat {
|
|||
const phy_interface_t *interface;
|
||||
int num_interfaces;
|
||||
int an_mode;
|
||||
int (*pma_config)(struct dw_xpcs *xpcs);
|
||||
};
|
||||
|
||||
struct xpcs_id {
|
||||
|
@ -168,7 +169,7 @@ static bool __xpcs_linkmode_supported(const struct xpcs_compat *compat,
|
|||
#define xpcs_linkmode_supported(compat, mode) \
|
||||
__xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
|
||||
|
||||
static int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
|
||||
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
|
||||
{
|
||||
u32 reg_addr = mdiobus_c45_addr(dev, reg);
|
||||
struct mii_bus *bus = xpcs->mdiodev->bus;
|
||||
|
@ -177,7 +178,7 @@ static int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
|
|||
return mdiobus_read(bus, addr, reg_addr);
|
||||
}
|
||||
|
||||
static int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
|
||||
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
|
||||
{
|
||||
u32 reg_addr = mdiobus_c45_addr(dev, reg);
|
||||
struct mii_bus *bus = xpcs->mdiodev->bus;
|
||||
|
@ -788,6 +789,12 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (compat->pma_config) {
|
||||
ret = compat->pma_config(xpcs);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1022,11 +1029,25 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
|
||||
[DW_XPCS_SGMII] = {
|
||||
.supported = xpcs_sgmii_features,
|
||||
.interface = xpcs_sgmii_interfaces,
|
||||
.num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
|
||||
.an_mode = DW_AN_C37_SGMII,
|
||||
.pma_config = nxp_sja1105_sgmii_pma_config,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct xpcs_id xpcs_id_list[] = {
|
||||
{
|
||||
.id = SYNOPSYS_XPCS_ID,
|
||||
.mask = SYNOPSYS_XPCS_MASK,
|
||||
.compat = synopsys_xpcs_compat,
|
||||
}, {
|
||||
.id = NXP_SJA1105_XPCS_ID,
|
||||
.mask = SYNOPSYS_XPCS_MASK,
|
||||
.compat = nxp_sja1105_xpcs_compat,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -60,10 +60,15 @@
|
|||
/* EEE Mode Control Register */
|
||||
#define DW_VR_MII_EEE_MCTRL0 0x8006
|
||||
#define DW_VR_MII_EEE_MCTRL1 0x800b
|
||||
#define DW_VR_MII_DIG_CTRL2 0x80e1
|
||||
|
||||
/* VR_MII_DIG_CTRL1 */
|
||||
#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
|
||||
|
||||
/* VR_MII_DIG_CTRL2 */
|
||||
#define DW_VR_MII_DIG_CTRL2_TX_POL_INV BIT(4)
|
||||
#define DW_VR_MII_DIG_CTRL2_RX_POL_INV BIT(0)
|
||||
|
||||
/* VR_MII_AN_CTRL */
|
||||
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
|
||||
#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
|
||||
|
@ -101,3 +106,8 @@
|
|||
|
||||
/* VR MII EEE Control 1 defines */
|
||||
#define DW_VR_MII_EEE_TRN_LPI BIT(0) /* Transparent Mode Enable */
|
||||
|
||||
int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
|
||||
int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
|
||||
|
||||
int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
|
||||
#define NXP_SJA1105_XPCS_ID 0x00000010
|
||||
|
||||
/* AN mode */
|
||||
#define DW_AN_C73 1
|
||||
#define DW_AN_C37_SGMII 2
|
||||
|
|
Loading…
Reference in New Issue