mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-17 22:49:02 +00:00
net: dsa: sja1105: add support for SGMII
The list of ports which support SGMII depending on switch generation is available here: https://www.kernel.org/doc/html/latest/networking/dsa/sja1105.html#port-compatibility-matrix SGMII can either be used to connect to an external PHY or to the host port. In the first case, the use of in-band autoneg is expected, in the last, in-band autoneg is expected to be turned off (fixed-link). So the driver supports both cases. SGMII support means configuring the PCS and PMA. The PCS is a Synopsys Designware XPCS, in Linux this has a separate driver but here it is embedded within the sja1105 driver. If needed it can be taken out later, although we would need a UCLASS_PCS for it, which we don't have atm. Nonetheless, I did go all the way to export an internal MDIO bus for PCS access, because it is nice to be able to debug the PCS through commands such as: => mdio read ethernet-switch@1-pcs 4 1f.0 Reading from bus ethernet-switch@1-pcs PHY at address 4: 31.0 - 0x1140 The internal MDIO bus is not registered with DM because there is no udevice on it, as mentioned. But the XPCS code can still be ripped out, as needed. I did not add support for 2500base-x because I do not expect this interface type to be used as a boot source for anybody, it would just add unnecessary bloat. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
This commit is contained in:
parent
f24b666b22
commit
7f7e73eee3
1 changed files with 570 additions and 1 deletions
|
@ -37,6 +37,7 @@ enum packing_op {
|
|||
#define SJA1105ET_FDB_BIN_SIZE 4
|
||||
#define SJA1105_SIZE_CGU_CMD 4
|
||||
#define SJA1105_SIZE_RESET_CMD 4
|
||||
#define SJA1105_SIZE_MDIO_CMD 4
|
||||
#define SJA1105_SIZE_SPI_MSG_HEADER 4
|
||||
#define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4)
|
||||
#define SJA1105_SIZE_DEVICE_ID 4
|
||||
|
@ -95,6 +96,8 @@ enum packing_op {
|
|||
|
||||
#define SJA1105_RSV_ADDR 0xffffffffffffffffull
|
||||
|
||||
#define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc)
|
||||
|
||||
#define DSA_8021Q_DIR_TX BIT(11)
|
||||
#define DSA_8021Q_PORT_SHIFT 0
|
||||
#define DSA_8021Q_PORT_MASK GENMASK(3, 0)
|
||||
|
@ -103,6 +106,89 @@ enum packing_op {
|
|||
|
||||
#define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000)
|
||||
|
||||
/* XPCS registers */
|
||||
|
||||
/* VR MII MMD registers offsets */
|
||||
#define DW_VR_MII_DIG_CTRL1 0x8000
|
||||
#define DW_VR_MII_AN_CTRL 0x8001
|
||||
#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)
|
||||
|
||||
/* VR_MII_AN_CTRL */
|
||||
#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3
|
||||
#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
|
||||
#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
|
||||
#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1
|
||||
#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
|
||||
#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
|
||||
|
||||
/* PMA registers */
|
||||
|
||||
/* LANE_DRIVER1_0 register */
|
||||
#define SJA1110_LANE_DRIVER1_0 0x8038
|
||||
#define SJA1110_TXDRV(x) (((x) << 12) & GENMASK(14, 12))
|
||||
|
||||
/* LANE_DRIVER2_0 register */
|
||||
#define SJA1110_LANE_DRIVER2_0 0x803a
|
||||
#define SJA1110_TXDRVTRIM_LSB(x) ((x) & GENMASK_ULL(15, 0))
|
||||
|
||||
/* LANE_DRIVER2_1 register */
|
||||
#define SJA1110_LANE_DRIVER2_1 0x803b
|
||||
#define SJA1110_LANE_DRIVER2_1_RSV BIT(9)
|
||||
#define SJA1110_TXDRVTRIM_MSB(x) (((x) & GENMASK_ULL(23, 16)) >> 16)
|
||||
|
||||
/* LANE_TRIM register */
|
||||
#define SJA1110_LANE_TRIM 0x8040
|
||||
#define SJA1110_TXTEN BIT(11)
|
||||
#define SJA1110_TXRTRIM(x) (((x) << 8) & GENMASK(10, 8))
|
||||
#define SJA1110_TXPLL_BWSEL BIT(7)
|
||||
#define SJA1110_RXTEN BIT(6)
|
||||
#define SJA1110_RXRTRIM(x) (((x) << 3) & GENMASK(5, 3))
|
||||
#define SJA1110_CDR_GAIN BIT(2)
|
||||
#define SJA1110_ACCOUPLE_RXVCM_EN BIT(0)
|
||||
|
||||
/* LANE_DATAPATH_1 register */
|
||||
#define SJA1110_LANE_DATAPATH_1 0x8037
|
||||
|
||||
/* POWERDOWN_ENABLE register */
|
||||
#define SJA1110_POWERDOWN_ENABLE 0x8041
|
||||
#define SJA1110_TXPLL_PD BIT(12)
|
||||
#define SJA1110_TXPD BIT(11)
|
||||
#define SJA1110_RXPKDETEN BIT(10)
|
||||
#define SJA1110_RXCH_PD BIT(9)
|
||||
#define SJA1110_RXBIAS_PD BIT(8)
|
||||
#define SJA1110_RESET_SER_EN BIT(7)
|
||||
#define SJA1110_RESET_SER BIT(6)
|
||||
#define SJA1110_RESET_DES BIT(5)
|
||||
#define SJA1110_RCVEN BIT(4)
|
||||
|
||||
/* RXPLL_CTRL0 register */
|
||||
#define SJA1110_RXPLL_CTRL0 0x8065
|
||||
#define SJA1110_RXPLL_FBDIV(x) (((x) << 2) & GENMASK(9, 2))
|
||||
|
||||
/* RXPLL_CTRL1 register */
|
||||
#define SJA1110_RXPLL_CTRL1 0x8066
|
||||
#define SJA1110_RXPLL_REFDIV(x) ((x) & GENMASK(4, 0))
|
||||
|
||||
/* TXPLL_CTRL0 register */
|
||||
#define SJA1110_TXPLL_CTRL0 0x806d
|
||||
#define SJA1110_TXPLL_FBDIV(x) ((x) & GENMASK(11, 0))
|
||||
|
||||
/* TXPLL_CTRL1 register */
|
||||
#define SJA1110_TXPLL_CTRL1 0x806e
|
||||
#define SJA1110_TXPLL_REFDIV(x) ((x) & GENMASK(5, 0))
|
||||
|
||||
/* RX_DATA_DETECT register */
|
||||
#define SJA1110_RX_DATA_DETECT 0x8045
|
||||
|
||||
/* RX_CDR_CTLE register */
|
||||
#define SJA1110_RX_CDR_CTLE 0x8042
|
||||
|
||||
/* UM10944.pdf Page 11, Table 2. Configuration Blocks */
|
||||
enum {
|
||||
BLKID_L2_POLICING = 0x06,
|
||||
|
@ -203,11 +289,18 @@ struct sja1105_static_config {
|
|||
struct sja1105_table tables[BLK_IDX_MAX];
|
||||
};
|
||||
|
||||
struct sja1105_xpcs_cfg {
|
||||
bool inband_an;
|
||||
int speed;
|
||||
};
|
||||
|
||||
struct sja1105_private {
|
||||
struct sja1105_static_config static_config;
|
||||
bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
|
||||
bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
|
||||
u16 pvid[SJA1105_MAX_NUM_PORTS];
|
||||
struct sja1105_xpcs_cfg xpcs_cfg[SJA1105_MAX_NUM_PORTS];
|
||||
struct mii_dev *mdio_pcs;
|
||||
const struct sja1105_info *info;
|
||||
struct udevice *dev;
|
||||
};
|
||||
|
@ -226,6 +319,7 @@ typedef enum {
|
|||
XMII_MODE_MII = 0,
|
||||
XMII_MODE_RMII = 1,
|
||||
XMII_MODE_RGMII = 2,
|
||||
XMII_MODE_SGMII = 3,
|
||||
} sja1105_phy_interface_t;
|
||||
|
||||
enum {
|
||||
|
@ -263,6 +357,7 @@ struct sja1105_regs {
|
|||
u64 rgmii_tx_clk[SJA1105_MAX_NUM_PORTS];
|
||||
u64 rmii_ref_clk[SJA1105_MAX_NUM_PORTS];
|
||||
u64 rmii_ext_tx_clk[SJA1105_MAX_NUM_PORTS];
|
||||
u64 pcs_base[SJA1105_MAX_NUM_PORTS];
|
||||
};
|
||||
|
||||
struct sja1105_info {
|
||||
|
@ -272,10 +367,15 @@ struct sja1105_info {
|
|||
const struct sja1105_regs *regs;
|
||||
int (*reset_cmd)(struct sja1105_private *priv);
|
||||
int (*setup_rgmii_delay)(struct sja1105_private *priv, int port);
|
||||
int (*pcs_mdio_read)(struct mii_dev *bus, int phy, int mmd, int reg);
|
||||
int (*pcs_mdio_write)(struct mii_dev *bus, int phy, int mmd, int reg,
|
||||
u16 val);
|
||||
int (*pma_config)(struct sja1105_private *priv, int port);
|
||||
const char *name;
|
||||
bool supports_mii[SJA1105_MAX_NUM_PORTS];
|
||||
bool supports_rmii[SJA1105_MAX_NUM_PORTS];
|
||||
bool supports_rgmii[SJA1105_MAX_NUM_PORTS];
|
||||
bool supports_sgmii[SJA1105_MAX_NUM_PORTS];
|
||||
const u64 port_speed[SJA1105_SPEED_MAX];
|
||||
};
|
||||
|
||||
|
@ -2030,6 +2130,233 @@ static int sja1105_rmii_clocking_setup(struct sja1105_private *priv, int port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sja1105_pcs_read(struct sja1105_private *priv, int addr,
|
||||
int devad, int regnum)
|
||||
{
|
||||
return priv->mdio_pcs->read(priv->mdio_pcs, addr, devad, regnum);
|
||||
}
|
||||
|
||||
static int sja1105_pcs_write(struct sja1105_private *priv, int addr,
|
||||
int devad, int regnum, u16 val)
|
||||
{
|
||||
return priv->mdio_pcs->write(priv->mdio_pcs, addr, devad, regnum, val);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static int sja1105_pma_config(struct sja1105_private *priv, int port)
|
||||
{
|
||||
return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
DW_VR_MII_DIG_CTRL2,
|
||||
DW_VR_MII_DIG_CTRL2_TX_POL_INV);
|
||||
}
|
||||
|
||||
static int sja1110_pma_config(struct sja1105_private *priv, int port)
|
||||
{
|
||||
u16 txpll_fbdiv = 0x19, txpll_refdiv = 0x1;
|
||||
u16 rxpll_fbdiv = 0x19, rxpll_refdiv = 0x1;
|
||||
u16 rx_cdr_ctle = 0x212a;
|
||||
u16 val;
|
||||
int rc;
|
||||
|
||||
/* Program TX PLL feedback divider and reference divider settings for
|
||||
* correct oscillation frequency.
|
||||
*/
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,
|
||||
SJA1110_TXPLL_FBDIV(txpll_fbdiv));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,
|
||||
SJA1110_TXPLL_REFDIV(txpll_refdiv));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Program transmitter amplitude and disable amplitude trimming */
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_LANE_DRIVER1_0, SJA1110_TXDRV(0x5));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
val = SJA1110_TXDRVTRIM_LSB(0xffffffull);
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_LANE_DRIVER2_0, val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
val = SJA1110_TXDRVTRIM_MSB(0xffffffull) | SJA1110_LANE_DRIVER2_1_RSV;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_LANE_DRIVER2_1, val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Enable input and output resistor terminations for low BER. */
|
||||
val = SJA1110_ACCOUPLE_RXVCM_EN | SJA1110_CDR_GAIN |
|
||||
SJA1110_RXRTRIM(4) | SJA1110_RXTEN | SJA1110_TXPLL_BWSEL |
|
||||
SJA1110_TXRTRIM(3) | SJA1110_TXTEN;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_LANE_TRIM,
|
||||
val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Select PCS as transmitter data source. */
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_LANE_DATAPATH_1, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Program RX PLL feedback divider and reference divider for correct
|
||||
* oscillation frequency.
|
||||
*/
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,
|
||||
SJA1110_RXPLL_FBDIV(rxpll_fbdiv));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,
|
||||
SJA1110_RXPLL_REFDIV(rxpll_refdiv));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Program threshold for receiver signal detector.
|
||||
* Enable control of RXPLL by receiver signal detector to disable RXPLL
|
||||
* when an input signal is not present.
|
||||
*/
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_RX_DATA_DETECT, 0x0005);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Enable TX and RX PLLs and circuits.
|
||||
* Release reset of PMA to enable data flow to/from PCS.
|
||||
*/
|
||||
rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_POWERDOWN_ENABLE);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
val = rc & ~(SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |
|
||||
SJA1110_RXBIAS_PD | SJA1110_RESET_SER_EN |
|
||||
SJA1110_RESET_SER | SJA1110_RESET_DES);
|
||||
val |= SJA1110_RXPKDETEN | SJA1110_RCVEN;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2,
|
||||
SJA1110_POWERDOWN_ENABLE, val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Program continuous-time linear equalizer (CTLE) settings. */
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,
|
||||
rx_cdr_ctle);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sja1105_xpcs_config_aneg_c37_sgmii(struct sja1105_private *priv,
|
||||
int port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc &= ~MDIO_AN_CTRL1_ENABLE;
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1,
|
||||
rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
|
||||
rc |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
|
||||
DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
|
||||
DW_VR_MII_PCS_MODE_MASK);
|
||||
rc |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
|
||||
DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
|
||||
DW_VR_MII_TX_CONFIG_MASK);
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
|
||||
rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (priv->xpcs_cfg[port].inband_an)
|
||||
rc |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
|
||||
else
|
||||
rc &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
|
||||
|
||||
rc = sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
|
||||
rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_pcs_read(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (priv->xpcs_cfg[port].inband_an)
|
||||
rc |= MDIO_AN_CTRL1_ENABLE;
|
||||
else
|
||||
rc &= ~MDIO_AN_CTRL1_ENABLE;
|
||||
|
||||
return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, rc);
|
||||
}
|
||||
|
||||
static int sja1105_xpcs_link_up_sgmii(struct sja1105_private *priv, int port)
|
||||
{
|
||||
int val = BMCR_FULLDPLX;
|
||||
|
||||
if (priv->xpcs_cfg[port].inband_an)
|
||||
return 0;
|
||||
|
||||
switch (priv->xpcs_cfg[port].speed) {
|
||||
case SPEED_1000:
|
||||
val = BMCR_SPEED1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
val = BMCR_SPEED100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
val = BMCR_SPEED10;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "Invalid PCS speed %d\n",
|
||||
priv->xpcs_cfg[port].speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return sja1105_pcs_write(priv, port, MDIO_MMD_VEND2, MDIO_CTRL1, val);
|
||||
}
|
||||
|
||||
static int sja1105_sgmii_setup(struct sja1105_private *priv, int port)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = sja1105_xpcs_config_aneg_c37_sgmii(priv, port);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_xpcs_link_up_sgmii(priv, port);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return priv->info->pma_config(priv, port);
|
||||
}
|
||||
|
||||
static int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
|
||||
{
|
||||
struct sja1105_xmii_params_entry *mii;
|
||||
|
@ -2054,6 +2381,9 @@ static int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
|
|||
case XMII_MODE_RGMII:
|
||||
rc = sja1105_rgmii_clocking_setup(priv, port, role);
|
||||
break;
|
||||
case XMII_MODE_SGMII:
|
||||
rc = sja1105_sgmii_setup(priv, port);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2077,6 +2407,188 @@ static int sja1105_clocking_setup(struct sja1105_private *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sja1105_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
|
||||
{
|
||||
u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
|
||||
struct sja1105_private *priv = bus->priv;
|
||||
const int size = SJA1105_SIZE_MDIO_CMD;
|
||||
u64 addr, tmp;
|
||||
int rc;
|
||||
|
||||
if (mmd == MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
if (!priv->info->supports_sgmii[phy])
|
||||
return -ENODEV;
|
||||
|
||||
addr = (mmd << 16) | (reg & GENMASK(15, 0));
|
||||
|
||||
if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
|
||||
return 0xffff;
|
||||
|
||||
rc = sja1105_xfer_buf(priv, SPI_READ, addr, packed_buf, size);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
|
||||
|
||||
return tmp & 0xffff;
|
||||
}
|
||||
|
||||
static int sja1105_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
|
||||
int reg, u16 val)
|
||||
{
|
||||
u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
|
||||
struct sja1105_private *priv = bus->priv;
|
||||
const int size = SJA1105_SIZE_MDIO_CMD;
|
||||
u64 addr, tmp;
|
||||
|
||||
if (mmd == MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
if (!priv->info->supports_sgmii[phy])
|
||||
return -ENODEV;
|
||||
|
||||
addr = (mmd << 16) | (reg & GENMASK(15, 0));
|
||||
tmp = val;
|
||||
|
||||
if (mmd != MDIO_MMD_VEND1 && mmd != MDIO_MMD_VEND2)
|
||||
return -ENODEV;
|
||||
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
|
||||
|
||||
return sja1105_xfer_buf(priv, SPI_WRITE, addr, packed_buf, size);
|
||||
}
|
||||
|
||||
static int sja1110_pcs_mdio_read(struct mii_dev *bus, int phy, int mmd, int reg)
|
||||
{
|
||||
struct sja1105_private *priv = bus->priv;
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
|
||||
const int size = SJA1105_SIZE_MDIO_CMD;
|
||||
int offset, bank;
|
||||
u64 addr, tmp;
|
||||
int rc;
|
||||
|
||||
if (mmd == MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
addr = (mmd << 16) | (reg & GENMASK(15, 0));
|
||||
|
||||
bank = addr >> 8;
|
||||
offset = addr & GENMASK(7, 0);
|
||||
|
||||
/* This addressing scheme reserves register 0xff for the bank address
|
||||
* register, so that can never be addressed.
|
||||
*/
|
||||
if (offset == 0xff)
|
||||
return -ENODEV;
|
||||
|
||||
tmp = bank;
|
||||
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
|
||||
|
||||
rc = sja1105_xfer_buf(priv, SPI_WRITE,
|
||||
regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
|
||||
packed_buf, size);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = sja1105_xfer_buf(priv, SPI_READ, regs->pcs_base[phy] + offset,
|
||||
packed_buf, size);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, UNPACK);
|
||||
|
||||
return tmp & 0xffff;
|
||||
}
|
||||
|
||||
static int sja1110_pcs_mdio_write(struct mii_dev *bus, int phy, int mmd,
|
||||
int reg, u16 val)
|
||||
{
|
||||
struct sja1105_private *priv = bus->priv;
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
u8 packed_buf[SJA1105_SIZE_MDIO_CMD] = {0};
|
||||
const int size = SJA1105_SIZE_MDIO_CMD;
|
||||
int offset, bank;
|
||||
u64 addr, tmp;
|
||||
int rc;
|
||||
|
||||
if (mmd == MDIO_DEVAD_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
|
||||
return -ENODEV;
|
||||
|
||||
addr = (mmd << 16) | (reg & GENMASK(15, 0));
|
||||
|
||||
bank = addr >> 8;
|
||||
offset = addr & GENMASK(7, 0);
|
||||
|
||||
/* This addressing scheme reserves register 0xff for the bank address
|
||||
* register, so that can never be addressed.
|
||||
*/
|
||||
if (offset == 0xff)
|
||||
return -ENODEV;
|
||||
|
||||
tmp = bank;
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
|
||||
|
||||
rc = sja1105_xfer_buf(priv, SPI_WRITE,
|
||||
regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
|
||||
packed_buf, size);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
tmp = val;
|
||||
sja1105_packing(packed_buf, &tmp, 31, 0, size, PACK);
|
||||
|
||||
return sja1105_xfer_buf(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
|
||||
packed_buf, size);
|
||||
}
|
||||
|
||||
static int sja1105_mdiobus_register(struct sja1105_private *priv)
|
||||
{
|
||||
struct udevice *dev = priv->dev;
|
||||
struct mii_dev *bus;
|
||||
int rc;
|
||||
|
||||
if (!priv->info->pcs_mdio_read || !priv->info->pcs_mdio_write)
|
||||
return 0;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(bus->name, MDIO_NAME_LEN, "%s-pcs", dev->name);
|
||||
bus->read = priv->info->pcs_mdio_read;
|
||||
bus->write = priv->info->pcs_mdio_write;
|
||||
bus->priv = priv;
|
||||
|
||||
rc = mdio_register(bus);
|
||||
if (rc) {
|
||||
mdio_free(bus);
|
||||
return rc;
|
||||
}
|
||||
|
||||
priv->mdio_pcs = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sja1105_mdiobus_unregister(struct sja1105_private *priv)
|
||||
{
|
||||
if (!priv->mdio_pcs)
|
||||
return;
|
||||
|
||||
mdio_unregister(priv->mdio_pcs);
|
||||
mdio_free(priv->mdio_pcs);
|
||||
}
|
||||
|
||||
static const struct sja1105_regs sja1105et_regs = {
|
||||
.device_id = 0x0,
|
||||
.prod_id = 0x100BC3,
|
||||
|
@ -2185,6 +2697,9 @@ static const struct sja1105_regs sja1110_regs = {
|
|||
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
|
||||
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
|
||||
SJA1105_RSV_ADDR},
|
||||
.pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
|
||||
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
|
||||
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
|
||||
};
|
||||
|
||||
enum sja1105_switch_id {
|
||||
|
@ -2279,6 +2794,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
|
||||
.reset_cmd = sja1105pqrs_reset_cmd,
|
||||
.regs = &sja1105pqrs_regs,
|
||||
.pcs_mdio_read = sja1105_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1105_pcs_mdio_write,
|
||||
.pma_config = sja1105_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 3,
|
||||
|
@ -2288,6 +2806,7 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.supports_mii = {true, true, true, true, true},
|
||||
.supports_rmii = {true, true, true, true, true},
|
||||
.supports_rgmii = {true, true, true, true, true},
|
||||
.supports_sgmii = {false, false, false, false, true},
|
||||
.name = "SJA1105R",
|
||||
},
|
||||
[SJA1105S] = {
|
||||
|
@ -2297,6 +2816,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1105pqrs_setup_rgmii_delay,
|
||||
.reset_cmd = sja1105pqrs_reset_cmd,
|
||||
.regs = &sja1105pqrs_regs,
|
||||
.pcs_mdio_read = sja1105_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1105_pcs_mdio_write,
|
||||
.pma_config = sja1105_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 3,
|
||||
|
@ -2306,6 +2828,7 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.supports_mii = {true, true, true, true, true},
|
||||
.supports_rmii = {true, true, true, true, true},
|
||||
.supports_rgmii = {true, true, true, true, true},
|
||||
.supports_sgmii = {false, false, false, false, true},
|
||||
.name = "SJA1105S",
|
||||
},
|
||||
[SJA1110A] = {
|
||||
|
@ -2315,6 +2838,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1110_setup_rgmii_delay,
|
||||
.reset_cmd = sja1110_reset_cmd,
|
||||
.regs = &sja1110_regs,
|
||||
.pcs_mdio_read = sja1110_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1110_pcs_mdio_write,
|
||||
.pma_config = sja1110_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 4,
|
||||
|
@ -2327,6 +2853,8 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
false, false, false, false, false, false},
|
||||
.supports_rgmii = {false, false, true, true, false,
|
||||
false, false, false, false, false, false},
|
||||
.supports_sgmii = {false, true, true, true, true,
|
||||
false, false, false, false, false, false},
|
||||
.name = "SJA1110A",
|
||||
},
|
||||
[SJA1110B] = {
|
||||
|
@ -2336,6 +2864,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1110_setup_rgmii_delay,
|
||||
.reset_cmd = sja1110_reset_cmd,
|
||||
.regs = &sja1110_regs,
|
||||
.pcs_mdio_read = sja1110_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1110_pcs_mdio_write,
|
||||
.pma_config = sja1110_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 4,
|
||||
|
@ -2348,6 +2879,8 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
false, false, false, false, false, false},
|
||||
.supports_rgmii = {false, false, true, true, false,
|
||||
false, false, false, false, false, false},
|
||||
.supports_sgmii = {false, false, false, true, true,
|
||||
false, false, false, false, false, false},
|
||||
.name = "SJA1110B",
|
||||
},
|
||||
[SJA1110C] = {
|
||||
|
@ -2357,6 +2890,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1110_setup_rgmii_delay,
|
||||
.reset_cmd = sja1110_reset_cmd,
|
||||
.regs = &sja1110_regs,
|
||||
.pcs_mdio_read = sja1110_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1110_pcs_mdio_write,
|
||||
.pma_config = sja1110_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 4,
|
||||
|
@ -2369,6 +2905,8 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
false, false, false, false, false, false},
|
||||
.supports_rgmii = {false, false, true, true, false,
|
||||
false, false, false, false, false, false},
|
||||
.supports_sgmii = {false, false, false, false, true,
|
||||
false, false, false, false, false, false},
|
||||
.name = "SJA1110C",
|
||||
},
|
||||
[SJA1110D] = {
|
||||
|
@ -2378,6 +2916,9 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
.setup_rgmii_delay = sja1110_setup_rgmii_delay,
|
||||
.reset_cmd = sja1110_reset_cmd,
|
||||
.regs = &sja1110_regs,
|
||||
.pcs_mdio_read = sja1110_pcs_mdio_read,
|
||||
.pcs_mdio_write = sja1110_pcs_mdio_write,
|
||||
.pma_config = sja1110_pma_config,
|
||||
.port_speed = {
|
||||
[SJA1105_SPEED_AUTO] = 0,
|
||||
[SJA1105_SPEED_10MBPS] = 4,
|
||||
|
@ -2390,6 +2931,8 @@ static const struct sja1105_info sja1105_info[] = {
|
|||
false, false, false, false, false, false},
|
||||
.supports_rgmii = {false, false, true, false, false,
|
||||
false, false, false, false, false, false},
|
||||
.supports_sgmii = {false, true, true, true, true,
|
||||
false, false, false, false, false, false},
|
||||
.name = "SJA1110D",
|
||||
},
|
||||
};
|
||||
|
@ -2541,8 +3084,12 @@ static int sja1105_static_config_reload(struct sja1105_private *priv)
|
|||
static int sja1105_port_probe(struct udevice *dev, int port,
|
||||
struct phy_device *phy)
|
||||
{
|
||||
struct sja1105_private *priv = dev_get_priv(dev);
|
||||
ofnode node = dsa_port_get_ofnode(dev, port);
|
||||
phy_interface_t phy_mode = phy->interface;
|
||||
|
||||
priv->xpcs_cfg[port].inband_an = ofnode_eth_uses_inband_aneg(node);
|
||||
|
||||
if (phy_mode == PHY_INTERFACE_MODE_MII ||
|
||||
phy_mode == PHY_INTERFACE_MODE_RMII) {
|
||||
phy->supported &= PHY_BASIC_FEATURES;
|
||||
|
@ -2593,6 +3140,13 @@ static int sja1105_port_enable(struct udevice *dev, int port,
|
|||
|
||||
mii->xmii_mode[port] = XMII_MODE_RGMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
if (!priv->info->supports_sgmii[port])
|
||||
goto unsupported;
|
||||
|
||||
mii->xmii_mode[port] = XMII_MODE_SGMII;
|
||||
mii->special[port] = true;
|
||||
break;
|
||||
unsupported:
|
||||
default:
|
||||
dev_err(dev, "Unsupported PHY mode %d on port %d!\n",
|
||||
|
@ -2621,7 +3175,10 @@ unsupported:
|
|||
}
|
||||
}
|
||||
|
||||
if (phy->speed == SPEED_1000) {
|
||||
if (mii->xmii_mode[port] == XMII_MODE_SGMII) {
|
||||
mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
|
||||
priv->xpcs_cfg[port].speed = phy->speed;
|
||||
} else if (phy->speed == SPEED_1000) {
|
||||
mac[port].speed = priv->info->port_speed[SJA1105_SPEED_1000MBPS];
|
||||
} else if (phy->speed == SPEED_100) {
|
||||
mac[port].speed = priv->info->port_speed[SJA1105_SPEED_100MBPS];
|
||||
|
@ -2688,7 +3245,18 @@ static int sja1105_init(struct sja1105_private *priv)
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = sja1105_mdiobus_register(priv);
|
||||
if (rc) {
|
||||
printf("Failed to register MDIO bus: %d\n", rc);
|
||||
goto err_mdiobus_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_mdiobus_register:
|
||||
sja1105_static_config_free(&priv->static_config);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sja1105_check_device_id(struct sja1105_private *priv)
|
||||
|
@ -2777,6 +3345,7 @@ static int sja1105_remove(struct udevice *dev)
|
|||
{
|
||||
struct sja1105_private *priv = dev_get_priv(dev);
|
||||
|
||||
sja1105_mdiobus_unregister(priv);
|
||||
sja1105_static_config_free(&priv->static_config);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue