@@ -14,6 +14,7 @@
#include <linux/irqreturn.h>
#include <linux/netdevice.h>
#include <linux/irq.h>
+#include <linux/phy.h>
/* The silicon design supports a maximum RX ring size of
* 32K entries. Based on current testing this maximum size
@@ -84,6 +85,12 @@ struct mlxbf_gige_mdio_gw {
struct mlxbf_gige_reg_param st1;
};
+struct mlxbf_gige_link_cfg {
+ void (*set_phy_link_mode)(struct phy_device *phydev);
+ void (*adjust_link)(struct net_device *netdev);
+ phy_interface_t phy_mode;
+};
+
struct mlxbf_gige {
void __iomem *base;
void __iomem *llu_base;
@@ -121,6 +128,7 @@ struct mlxbf_gige {
struct mlxbf_gige_stats stats;
u8 hw_version;
struct mlxbf_gige_mdio_gw *mdio_gw;
+ int prev_speed;
};
/* Rx Work Queue Element definitions */
@@ -263,13 +263,99 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = {
.ndo_get_stats64 = mlxbf_gige_get_stats64,
};
-static void mlxbf_gige_adjust_link(struct net_device *netdev)
+static void mlxbf_gige_bf2_adjust_link(struct net_device *netdev)
{
struct phy_device *phydev = netdev->phydev;
phy_print_status(phydev);
}
+static void mlxbf_gige_bf3_adjust_link(struct net_device *netdev)
+{
+ struct mlxbf_gige *priv = netdev_priv(netdev);
+ struct phy_device *phydev = netdev->phydev;
+ u8 sgmii_mode;
+ u16 ipg_size;
+ u32 val;
+
+ if (phydev->link && phydev->speed != priv->prev_speed) {
+ switch (phydev->speed) {
+ case 1000:
+ ipg_size = MLXBF_GIGE_1G_IPG_SIZE;
+ sgmii_mode = MLXBF_GIGE_1G_SGMII_MODE;
+ break;
+ case 100:
+ ipg_size = MLXBF_GIGE_100M_IPG_SIZE;
+ sgmii_mode = MLXBF_GIGE_100M_SGMII_MODE;
+ break;
+ case 10:
+ ipg_size = MLXBF_GIGE_10M_IPG_SIZE;
+ sgmii_mode = MLXBF_GIGE_10M_SGMII_MODE;
+ break;
+ default:
+ return;
+ }
+
+ val = readl(priv->plu_base + MLXBF_GIGE_PLU_TX_REG0);
+ val &= ~(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK | MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK);
+ val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK, ipg_size);
+ val |= FIELD_PREP(MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK, sgmii_mode);
+ writel(val, priv->plu_base + MLXBF_GIGE_PLU_TX_REG0);
+
+ val = readl(priv->plu_base + MLXBF_GIGE_PLU_RX_REG0);
+ val &= ~MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK;
+ val |= FIELD_PREP(MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK, sgmii_mode);
+ writel(val, priv->plu_base + MLXBF_GIGE_PLU_RX_REG0);
+
+ priv->prev_speed = phydev->speed;
+ }
+
+ phy_print_status(phydev);
+}
+
+static void mlxbf_gige_bf2_set_phy_link_mode(struct phy_device *phydev)
+{
+ /* MAC only supports 1000T full duplex mode */
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+
+ /* Only symmetric pause with flow control enabled is supported so no
+ * need to negotiate pause.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
+}
+
+static void mlxbf_gige_bf3_set_phy_link_mode(struct phy_device *phydev)
+{
+ /* MAC only supports full duplex mode */
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+
+ /* Only symmetric pause with flow control enabled is supported so no
+ * need to negotiate pause.
+ */
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
+}
+
+static struct mlxbf_gige_link_cfg mlxbf_gige_link_cfgs[] = {
+ [MLXBF_GIGE_VERSION_BF2] = {
+ .set_phy_link_mode = mlxbf_gige_bf2_set_phy_link_mode,
+ .adjust_link = mlxbf_gige_bf2_adjust_link,
+ .phy_mode = PHY_INTERFACE_MODE_GMII
+ },
+ [MLXBF_GIGE_VERSION_BF3] = {
+ .set_phy_link_mode = mlxbf_gige_bf3_set_phy_link_mode,
+ .adjust_link = mlxbf_gige_bf3_adjust_link,
+ .phy_mode = PHY_INTERFACE_MODE_SGMII
+ }
+};
+
static int mlxbf_gige_probe(struct platform_device *pdev)
{
struct phy_device *phydev;
@@ -359,25 +445,14 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
phydev->irq = phy_irq;
err = phy_connect_direct(netdev, phydev,
- mlxbf_gige_adjust_link,
- PHY_INTERFACE_MODE_GMII);
+ mlxbf_gige_link_cfgs[priv->hw_version].adjust_link,
+ mlxbf_gige_link_cfgs[priv->hw_version].phy_mode);
if (err) {
dev_err(&pdev->dev, "Could not attach to PHY\n");
goto out;
}
- /* MAC only supports 1000T full duplex mode */
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
-
- /* Only symmetric pause with flow control enabled is supported so no
- * need to negotiate pause.
- */
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising);
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising);
+ mlxbf_gige_link_cfgs[priv->hw_version].set_phy_link_mode(phydev);
/* Display information about attached PHY device */
phy_attached_info(phydev);
@@ -8,6 +8,8 @@
#ifndef __MLXBF_GIGE_REGS_H__
#define __MLXBF_GIGE_REGS_H__
+#include <linux/bitfield.h>
+
#define MLXBF_GIGE_VERSION 0x0000
#define MLXBF_GIGE_VERSION_BF2 0x0
#define MLXBF_GIGE_VERSION_BF3 0x1
@@ -78,4 +80,23 @@
*/
#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8)
+#define MLXBF_GIGE_PLU_TX_REG0 0x80
+#define MLXBF_GIGE_PLU_TX_IPG_SIZE_MASK GENMASK(11, 0)
+#define MLXBF_GIGE_PLU_TX_SGMII_MODE_MASK GENMASK(15, 14)
+
+#define MLXBF_GIGE_PLU_RX_REG0 0x10
+#define MLXBF_GIGE_PLU_RX_SGMII_MODE_MASK GENMASK(25, 24)
+
+#define MLXBF_GIGE_1G_SGMII_MODE 0x0
+#define MLXBF_GIGE_10M_SGMII_MODE 0x1
+#define MLXBF_GIGE_100M_SGMII_MODE 0x2
+
+/* ipg_size default value for 1G is fixed by HW to 11 + End = 12.
+ * So for 100M it is 12 * 10 - 1 = 119
+ * For 10M, it is 12 * 100 - 1 = 1199
+ */
+#define MLXBF_GIGE_1G_IPG_SIZE 11
+#define MLXBF_GIGE_100M_IPG_SIZE 119
+#define MLXBF_GIGE_10M_IPG_SIZE 1199
+
#endif /* !defined(__MLXBF_GIGE_REGS_H__) */