Skip to content

Commit 46682cb

Browse files
wvoondavem330
authored andcommitted
net: stmmac: enable Intel mGbE 2.5Gbps link speed
The Intel mGbE supports 2.5Gbps link speed by increasing the clock rate by 2.5 times of the original rate. In this mode, the serdes/PHY operates at a serial baud rate of 3.125 Gbps and the PCS data path and GMII interface of the MAC operate at 312.5 MHz instead of 125 MHz. For Intel mGbE, the overclocking of 2.5 times clock rate to support 2.5G is only able to be configured in the BIOS during boot time. Kernel driver has no access to modify the clock rate for 1Gbps/2.5G mode. The way to determined the current 1G/2.5G mode is by reading a dedicated adhoc register through mdio bus. In short, after the system boot up, it is either in 1G mode or 2.5G mode which not able to be changed on the fly. Compared to 1G mode, the 2.5G mode selects the 2500BASEX as PHY interface and disables the xpcs_an_inband. This is to cater for some PHYs that only supports 2500BASEX PHY interface with no autonegotiation. v2: remove MAC supported link speed masking v3: Restructure to introduce intel_speed_mode_2500() to read serdes registers for max speed supported and select the appropritate configuration. Use max_speed to determine the supported link speed mask. Signed-off-by: Voon Weifeng <[email protected]> Signed-off-by: Michael Sit Wei Hong <[email protected]> Reviewed-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f27abde commit 46682cb

File tree

5 files changed

+69
-1
lines changed

5 files changed

+69
-1
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ static int intel_serdes_powerup(struct net_device *ndev, void *priv_data)
102102

103103
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
104104

105+
/* Set the serdes rate and the PCLK rate */
106+
data = mdiobus_read(priv->mii, serdes_phy_addr,
107+
SERDES_GCR0);
108+
109+
data &= ~SERDES_RATE_MASK;
110+
data &= ~SERDES_PCLK_MASK;
111+
112+
if (priv->plat->max_speed == 2500)
113+
data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
114+
SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
115+
else
116+
data |= SERDES_RATE_PCIE_GEN1 << SERDES_RATE_PCIE_SHIFT |
117+
SERDES_PCLK_70MHZ << SERDES_PCLK_SHIFT;
118+
119+
mdiobus_write(priv->mii, serdes_phy_addr, SERDES_GCR0, data);
120+
105121
/* assert clk_req */
106122
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
107123
data |= SERDES_PLL_CLK;
@@ -230,6 +246,32 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data)
230246
}
231247
}
232248

249+
static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
250+
{
251+
struct intel_priv_data *intel_priv = intel_data;
252+
struct stmmac_priv *priv = netdev_priv(ndev);
253+
int serdes_phy_addr = 0;
254+
u32 data = 0;
255+
256+
serdes_phy_addr = intel_priv->mdio_adhoc_addr;
257+
258+
/* Determine the link speed mode: 2.5Gbps/1Gbps */
259+
data = mdiobus_read(priv->mii, serdes_phy_addr,
260+
SERDES_GCR);
261+
262+
if (((data & SERDES_LINK_MODE_MASK) >> SERDES_LINK_MODE_SHIFT) ==
263+
SERDES_LINK_MODE_2G5) {
264+
dev_info(priv->device, "Link Speed Mode: 2.5Gbps\n");
265+
priv->plat->max_speed = 2500;
266+
priv->plat->phy_interface = PHY_INTERFACE_MODE_2500BASEX;
267+
priv->plat->mdio_bus_data->xpcs_an_inband = false;
268+
} else {
269+
priv->plat->max_speed = 1000;
270+
priv->plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
271+
priv->plat->mdio_bus_data->xpcs_an_inband = true;
272+
}
273+
}
274+
233275
/* Program PTP Clock Frequency for different variant of
234276
* Intel mGBE that has slightly different GPO mapping
235277
*/
@@ -586,7 +628,7 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
586628
{
587629
plat->bus_id = 1;
588630
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
589-
631+
plat->speed_mode_2500 = intel_speed_mode_2500;
590632
plat->serdes_powerup = intel_serdes_powerup;
591633
plat->serdes_powerdown = intel_serdes_powerdown;
592634

@@ -639,6 +681,7 @@ static int ehl_pse0_sgmii1g_data(struct pci_dev *pdev,
639681
struct plat_stmmacenet_data *plat)
640682
{
641683
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
684+
plat->speed_mode_2500 = intel_speed_mode_2500;
642685
plat->serdes_powerup = intel_serdes_powerup;
643686
plat->serdes_powerdown = intel_serdes_powerdown;
644687
return ehl_pse0_common_data(pdev, plat);
@@ -677,6 +720,7 @@ static int ehl_pse1_sgmii1g_data(struct pci_dev *pdev,
677720
struct plat_stmmacenet_data *plat)
678721
{
679722
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
723+
plat->speed_mode_2500 = intel_speed_mode_2500;
680724
plat->serdes_powerup = intel_serdes_powerup;
681725
plat->serdes_powerdown = intel_serdes_powerdown;
682726
return ehl_pse1_common_data(pdev, plat);
@@ -711,6 +755,7 @@ static int tgl_sgmii_phy0_data(struct pci_dev *pdev,
711755
{
712756
plat->bus_id = 1;
713757
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
758+
plat->speed_mode_2500 = intel_speed_mode_2500;
714759
plat->serdes_powerup = intel_serdes_powerup;
715760
plat->serdes_powerdown = intel_serdes_powerdown;
716761
return tgl_common_data(pdev, plat);
@@ -725,6 +770,7 @@ static int tgl_sgmii_phy1_data(struct pci_dev *pdev,
725770
{
726771
plat->bus_id = 2;
727772
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
773+
plat->speed_mode_2500 = intel_speed_mode_2500;
728774
plat->serdes_powerup = intel_serdes_powerup;
729775
plat->serdes_powerdown = intel_serdes_powerdown;
730776
return tgl_common_data(pdev, plat);

drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define POLL_DELAY_US 8
1010

1111
/* SERDES Register */
12+
#define SERDES_GCR 0x0 /* Global Conguration */
1213
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
1314
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */
1415

@@ -17,8 +18,20 @@
1718
#define SERDES_PHY_RX_CLK BIT(1) /* PSE SGMII PHY rx clk */
1819
#define SERDES_RST BIT(2) /* Serdes Reset */
1920
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
21+
#define SERDES_RATE_MASK GENMASK(9, 8)
22+
#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
23+
#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
24+
#define SERDES_LINK_MODE_SHIFT 1
2025
#define SERDES_PWR_ST_SHIFT 4
2126
#define SERDES_PWR_ST_P0 0x0
2227
#define SERDES_PWR_ST_P3 0x3
28+
#define SERDES_LINK_MODE_2G5 0x3
29+
#define SERSED_LINK_MODE_1G 0x2
30+
#define SERDES_PCLK_37p5MHZ 0x0
31+
#define SERDES_PCLK_70MHZ 0x1
32+
#define SERDES_RATE_PCIE_GEN1 0x0
33+
#define SERDES_RATE_PCIE_GEN2 0x1
34+
#define SERDES_RATE_PCIE_SHIFT 8
35+
#define SERDES_PCLK_SHIFT 12
2336

2437
#endif /* __DWMAC_INTEL_H__ */

drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,7 @@ int dwmac4_setup(struct stmmac_priv *priv)
13581358
mac->link.speed10 = GMAC_CONFIG_PS;
13591359
mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
13601360
mac->link.speed1000 = 0;
1361+
mac->link.speed2500 = GMAC_CONFIG_FES;
13611362
mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
13621363
mac->mii.addr = GMAC_MDIO_ADDR;
13631364
mac->mii.data = GMAC_MDIO_DATA;

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,10 @@ static void stmmac_validate(struct phylink_config *config,
931931
if ((max_speed > 0) && (max_speed < 1000)) {
932932
phylink_set(mask, 1000baseT_Full);
933933
phylink_set(mask, 1000baseX_Full);
934+
} else if (priv->plat->has_gmac4) {
935+
if (!max_speed || max_speed >= 2500)
936+
phylink_set(mac_supported, 2500baseT_Full);
937+
phylink_set(mac_supported, 2500baseX_Full);
934938
} else if (priv->plat->has_xgmac) {
935939
if (!max_speed || (max_speed >= 2500)) {
936940
phylink_set(mac_supported, 2500baseT_Full);
@@ -6993,6 +6997,9 @@ int stmmac_dvr_probe(struct device *device,
69936997
}
69946998
}
69956999

7000+
if (priv->plat->speed_mode_2500)
7001+
priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv);
7002+
69967003
if (priv->plat->mdio_bus_data) {
69977004
if (priv->plat->mdio_bus_data->has_xpcs) {
69987005
ret = stmmac_xpcs_setup(priv->mii);

include/linux/stmmac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ struct plat_stmmacenet_data {
223223
void (*fix_mac_speed)(void *priv, unsigned int speed);
224224
int (*serdes_powerup)(struct net_device *ndev, void *priv);
225225
void (*serdes_powerdown)(struct net_device *ndev, void *priv);
226+
void (*speed_mode_2500)(struct net_device *ndev, void *priv);
226227
void (*ptp_clk_freq_config)(void *priv);
227228
int (*init)(struct platform_device *pdev, void *priv);
228229
void (*exit)(struct platform_device *pdev, void *priv);

0 commit comments

Comments
 (0)