diff options
Diffstat (limited to 'drivers/phy')
-rw-r--r-- | drivers/phy/microchip/lan966x_serdes.c | 99 | ||||
-rw-r--r-- | drivers/phy/microchip/lan966x_serdes_regs.h | 42 |
2 files changed, 129 insertions, 12 deletions
diff --git a/drivers/phy/microchip/lan966x_serdes.c b/drivers/phy/microchip/lan966x_serdes.c index e86a879b92b5..fbc725ffa4ab 100644 --- a/drivers/phy/microchip/lan966x_serdes.c +++ b/drivers/phy/microchip/lan966x_serdes.c @@ -42,7 +42,10 @@ #define SERDES_MUX_QSGMII(i, p, m, c) \ SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_QSGMII, m, c) #define SERDES_MUX_RGMII(i, p, m, c) \ - SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c) + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_TXID, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_RXID, m, c), \ + SERDES_MUX(i, p, PHY_MODE_ETHERNET, PHY_INTERFACE_MODE_RGMII_ID, m, c) static void lan_rmw_(u32 val, u32 mask, void __iomem *mem, u32 offset) { @@ -94,21 +97,29 @@ static const struct serdes_mux lan966x_serdes_muxes[] = { HSIO_HW_CFG_SD6G_1_CFG_SET(1)), SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG | - HSIO_HW_CFG_RGMII_ENA, - HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, + HSIO_HW_CFG_RGMII_0_CFG_SET(0) | + HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(2))), SERDES_MUX_RGMII(RGMII(1), 3, HSIO_HW_CFG_RGMII_1_CFG | - HSIO_HW_CFG_RGMII_ENA, - HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, + HSIO_HW_CFG_RGMII_1_CFG_SET(0) | + HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(3))), SERDES_MUX_RGMII(RGMII(0), 5, HSIO_HW_CFG_RGMII_0_CFG | - HSIO_HW_CFG_RGMII_ENA, + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, HSIO_HW_CFG_RGMII_0_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(0))), + HSIO_HW_CFG_RGMII_ENA_SET(BIT(0)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(5))), SERDES_MUX_RGMII(RGMII(1), 6, HSIO_HW_CFG_RGMII_1_CFG | - HSIO_HW_CFG_RGMII_ENA, + HSIO_HW_CFG_RGMII_ENA | + HSIO_HW_CFG_GMII_ENA, HSIO_HW_CFG_RGMII_1_CFG_SET(BIT(0)) | - HSIO_HW_CFG_RGMII_ENA_SET(BIT(1))), + HSIO_HW_CFG_RGMII_ENA_SET(BIT(1)) | + HSIO_HW_CFG_GMII_ENA_SET(BIT(6))), }; struct serdes_ctrl { @@ -382,6 +393,67 @@ static int lan966x_sd6g40_setup(struct serdes_macro *macro, u32 idx, int mode) return lan966x_sd6g40_setup_lane(macro, conf, idx); } +static int lan966x_rgmii_setup(struct serdes_macro *macro, u32 idx, int mode) +{ + bool tx_delay = false; + bool rx_delay = false; + + /* Configure RGMII */ + lan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) | + HSIO_RGMII_CFG_RGMII_TX_RST_SET(0) | + HSIO_RGMII_CFG_TX_CLK_CFG_SET(macro->speed == SPEED_1000 ? 1 : + macro->speed == SPEED_100 ? 2 : + macro->speed == SPEED_10 ? 3 : 0), + HSIO_RGMII_CFG_RGMII_RX_RST | + HSIO_RGMII_CFG_RGMII_TX_RST | + HSIO_RGMII_CFG_TX_CLK_CFG, + macro->ctrl->regs, HSIO_RGMII_CFG(idx)); + + if (mode == PHY_INTERFACE_MODE_RGMII || + mode == PHY_INTERFACE_MODE_RGMII_TXID) + rx_delay = true; + + if (mode == PHY_INTERFACE_MODE_RGMII || + mode == PHY_INTERFACE_MODE_RGMII_RXID) + tx_delay = true; + + /* Setup DLL configuration */ + lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) | + HSIO_DLL_CFG_DLL_ENA_SET(rx_delay), + HSIO_DLL_CFG_DLL_RST | + HSIO_DLL_CFG_DLL_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2)); + + lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(rx_delay), + HSIO_DLL_CFG_DELAY_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x0 : 0x2)); + + lan_rmw(HSIO_DLL_CFG_DLL_RST_SET(0) | + HSIO_DLL_CFG_DLL_ENA_SET(tx_delay), + HSIO_DLL_CFG_DLL_RST | + HSIO_DLL_CFG_DLL_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3)); + + lan_rmw(HSIO_DLL_CFG_DELAY_ENA_SET(tx_delay), + HSIO_DLL_CFG_DELAY_ENA, + macro->ctrl->regs, HSIO_DLL_CFG(idx == 0 ? 0x1 : 0x3)); + + return 0; +} + +static int serdes_set_speed(struct phy *phy, int speed) +{ + struct serdes_macro *macro = phy_get_drvdata(phy); + + if (!phy_interface_mode_is_rgmii(macro->mode)) + return 0; + + macro->speed = speed; + lan966x_rgmii_setup(macro, macro->idx - (SERDES6G_MAX + 1), macro->mode); + + return 0; +} + static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct serdes_macro *macro = phy_get_drvdata(phy); @@ -424,7 +496,9 @@ static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) macro->mode); if (macro->idx < RGMII_MAX) - return 0; + return lan966x_rgmii_setup(macro, + macro->idx - (SERDES6G_MAX + 1), + macro->mode); return -EOPNOTSUPP; } @@ -434,6 +508,7 @@ static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) static const struct phy_ops serdes_ops = { .set_mode = serdes_set_mode, + .set_speed = serdes_set_speed, .owner = THIS_MODULE, }; diff --git a/drivers/phy/microchip/lan966x_serdes_regs.h b/drivers/phy/microchip/lan966x_serdes_regs.h index ea30f64ffd5c..ac54cd01fea6 100644 --- a/drivers/phy/microchip/lan966x_serdes_regs.h +++ b/drivers/phy/microchip/lan966x_serdes_regs.h @@ -206,4 +206,46 @@ enum lan966x_target { #define HSIO_HW_CFG_QSGMII_ENA_GET(x)\ FIELD_GET(HSIO_HW_CFG_QSGMII_ENA, x) +/* HSIO:HW_CFGSTAT:RGMII_CFG */ +#define HSIO_RGMII_CFG(r) __REG(TARGET_HSIO, 0, 1, 104, 0, 1, 52, 20, r, 2, 4) + +#define HSIO_RGMII_CFG_TX_CLK_CFG GENMASK(4, 2) +#define HSIO_RGMII_CFG_TX_CLK_CFG_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_TX_CLK_CFG, x) +#define HSIO_RGMII_CFG_TX_CLK_CFG_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_TX_CLK_CFG, x) + +#define HSIO_RGMII_CFG_RGMII_TX_RST BIT(1) +#define HSIO_RGMII_CFG_RGMII_TX_RST_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_RGMII_TX_RST, x) +#define HSIO_RGMII_CFG_RGMII_TX_RST_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_RGMII_TX_RST, x) + +#define HSIO_RGMII_CFG_RGMII_RX_RST BIT(0) +#define HSIO_RGMII_CFG_RGMII_RX_RST_SET(x)\ + FIELD_PREP(HSIO_RGMII_CFG_RGMII_RX_RST, x) +#define HSIO_RGMII_CFG_RGMII_RX_RST_GET(x)\ + FIELD_GET(HSIO_RGMII_CFG_RGMII_RX_RST, x) + +/* HSIO:HW_CFGSTAT:DLL_CFG */ +#define HSIO_DLL_CFG(r) __REG(TARGET_HSIO, 0, 1, 104, 0, 1, 52, 36, r, 4, 4) + +#define HSIO_DLL_CFG_DELAY_ENA BIT(2) +#define HSIO_DLL_CFG_DELAY_ENA_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DELAY_ENA, x) +#define HSIO_DLL_CFG_DELAY_ENA_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DELAY_ENA, x) + +#define HSIO_DLL_CFG_DLL_ENA BIT(1) +#define HSIO_DLL_CFG_DLL_ENA_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DLL_ENA, x) +#define HSIO_DLL_CFG_DLL_ENA_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DLL_ENA, x) + +#define HSIO_DLL_CFG_DLL_RST BIT(0) +#define HSIO_DLL_CFG_DLL_RST_SET(x)\ + FIELD_PREP(HSIO_DLL_CFG_DLL_RST, x) +#define HSIO_DLL_CFG_DLL_RST_GET(x)\ + FIELD_GET(HSIO_DLL_CFG_DLL_RST, x) + #endif /* _LAN966X_HSIO_REGS_H_ */ |