All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support
@ 2022-11-09 22:47 David Thompson
  2022-11-09 22:47 ` [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3 David Thompson
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: David Thompson @ 2022-11-09 22:47 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: netdev, cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	David Thompson

This patch series adds driver logic to the "mlxbf_gige"
Ethernet driver in order to support the third generation 
BlueField SoC (BF3).  The existing "mlxbf_gige" driver is
extended with BF3-specific logic and run-time decisions
are made by the driver depending on the SoC generation
(BF2 vs. BF3).

The BF3 SoC is similar to BF2 SoC with regards to transmit
and receive packet processing:
       * Driver rings usage; consumer & producer indices
       * Single queue for receive and transmit
       * DMA operation

The differences between BF3 and BF2 are:
       * In addition to supporting 1Gbps interface speed, the BF3 SoC
         adds support for 10Mbps and 100Mbps interface speeds
       * BF3 requires SerDes config logic to support its SGMII interface
       * BF3 adds support for "ethtool -s" for interface speed config
       * BF3 utilizes different MDIO logic for accessing the
         board-level PHY device

Testing
  - Successful build of kernel for ARM64, ARM32, X86_64
  - Tested ARM64 build on FastModels, Palladium, SoC

v1 -> v2:
  - Fixed build failures in "build_32bit" and "build_allmodconfig_warn"
  - Removed use of spinlock in BF3 "adjust_link" callback
  - Added use of ARRAY_SIZE() where appropriate
  - Added "set_link_ksettings" ethtool callback for BF2 and BF3

David Thompson (4):
  mlxbf_gige: add MDIO support for BlueField-3
  mlxbf_gige: support 10M/100M/1G speeds on BlueField-3
  mlxbf_gige: add BlueField-3 Serdes configuration
  mlxbf_gige: add "set_link_ksettings" ethtool callback

 .../net/ethernet/mellanox/mlxbf_gige/Makefile |    3 +-
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |   31 +-
 .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c  |    1 +
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     |  164 ++-
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c     |  185 +--
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h |   53 +
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h |   54 +
 .../mellanox/mlxbf_gige/mlxbf_gige_regs.h     |   22 +
 .../mellanox/mlxbf_gige/mlxbf_gige_uphy.c     | 1173 +++++++++++++++++
 .../mellanox/mlxbf_gige/mlxbf_gige_uphy.h     |  398 ++++++
 10 files changed, 1987 insertions(+), 97 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h

-- 
2.30.1


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3
  2022-11-09 22:47 [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support David Thompson
@ 2022-11-09 22:47 ` David Thompson
  2022-11-10 13:24   ` Andrew Lunn
  2022-11-09 22:47 ` [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3 David Thompson
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 19+ messages in thread
From: David Thompson @ 2022-11-09 22:47 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: netdev, cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	David Thompson, Asmaa Mnebhi

This patch adds initial MDIO support for the BlueField-3
SoC. Separate header files for the BlueField-2 and the
BlueField-3 SoCs have been created.  These header files
hold the SoC-specific MDIO macros since the register
offsets and bit fields have changed.  Also, in BlueField-3
there is a separate register for writing and reading the
MDIO data.  Finally, instead of having "if" statements
everywhere to differentiate between SoC-specific logic,
a mlxbf_gige_mdio_gw_t struct was created for this purpose.

Signed-off-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
---
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |  19 ++
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     |   2 +
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c     | 172 +++++++++++++-----
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h |  53 ++++++
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h |  54 ++++++
 .../mellanox/mlxbf_gige/mlxbf_gige_regs.h     |   1 +
 6 files changed, 251 insertions(+), 50 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index 5a1027b07215..421a0b1b766c 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -67,6 +67,23 @@ struct mlxbf_gige_stats {
 	u64 rx_filter_discard_pkts;
 };
 
+struct mlxbf_gige_reg_param {
+	u32 mask;
+	u32 shift;
+};
+
+struct mlxbf_gige_mdio_gw {
+	u32 gw_address;
+	u32 read_data_address;
+	struct mlxbf_gige_reg_param busy;
+	struct mlxbf_gige_reg_param write_data;
+	struct mlxbf_gige_reg_param read_data;
+	struct mlxbf_gige_reg_param devad;
+	struct mlxbf_gige_reg_param partad;
+	struct mlxbf_gige_reg_param opcode;
+	struct mlxbf_gige_reg_param st1;
+};
+
 struct mlxbf_gige {
 	void __iomem *base;
 	void __iomem *llu_base;
@@ -102,6 +119,8 @@ struct mlxbf_gige {
 	u8 valid_polarity;
 	struct napi_struct napi;
 	struct mlxbf_gige_stats stats;
+	u8 hw_version;
+	struct mlxbf_gige_mdio_gw *mdio_gw;
 };
 
 /* Rx Work Queue Element definitions */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index 2292d63a279c..e08c07e914c1 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -315,6 +315,8 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
 
 	spin_lock_init(&priv->lock);
 
+	priv->hw_version = readq(base + MLXBF_GIGE_VERSION);
+
 	/* Attach MDIO device */
 	err = mlxbf_gige_mdio_probe(pdev, priv);
 	if (err)
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
index aa780b1614a3..7ac06fd31011 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
@@ -23,9 +23,75 @@
 
 #include "mlxbf_gige.h"
 #include "mlxbf_gige_regs.h"
+#include "mlxbf_gige_mdio_bf2.h"
+#include "mlxbf_gige_mdio_bf3.h"
 
-#define MLXBF_GIGE_MDIO_GW_OFFSET	0x0
-#define MLXBF_GIGE_MDIO_CFG_OFFSET	0x4
+static struct mlxbf_gige_mdio_gw mlxbf_gige_mdio_gw_t[] = {
+	[MLXBF_GIGE_VERSION_BF2] = {
+		.gw_address = MLXBF2_GIGE_MDIO_GW_OFFSET,
+		.read_data_address = MLXBF2_GIGE_MDIO_GW_OFFSET,
+		.busy = {
+			.mask = MLXBF2_GIGE_MDIO_GW_BUSY_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_BUSY_SHIFT,
+		},
+		.read_data = {
+			.mask = MLXBF2_GIGE_MDIO_GW_AD_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_AD_SHIFT,
+		},
+		.write_data = {
+			.mask = MLXBF2_GIGE_MDIO_GW_AD_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_AD_SHIFT,
+		},
+		.devad = {
+			.mask = MLXBF2_GIGE_MDIO_GW_DEVAD_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_DEVAD_SHIFT,
+		},
+		.partad = {
+			.mask = MLXBF2_GIGE_MDIO_GW_PARTAD_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_PARTAD_SHIFT,
+		},
+		.opcode = {
+			.mask = MLXBF2_GIGE_MDIO_GW_OPCODE_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_OPCODE_SHIFT,
+		},
+		.st1 = {
+			.mask = MLXBF2_GIGE_MDIO_GW_ST1_MASK,
+			.shift = MLXBF2_GIGE_MDIO_GW_ST1_SHIFT,
+		},
+	},
+	[MLXBF_GIGE_VERSION_BF3] = {
+		.gw_address = MLXBF3_GIGE_MDIO_GW_OFFSET,
+		.read_data_address = MLXBF3_GIGE_MDIO_DATA_READ,
+		.busy = {
+			.mask = MLXBF3_GIGE_MDIO_GW_BUSY_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_BUSY_SHIFT,
+		},
+		.read_data = {
+			.mask = MLXBF3_GIGE_MDIO_GW_DATA_READ_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_DATA_READ_SHIFT,
+		},
+		.write_data = {
+			.mask = MLXBF3_GIGE_MDIO_GW_DATA_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_DATA_SHIFT,
+		},
+		.devad = {
+			.mask = MLXBF3_GIGE_MDIO_GW_DEVAD_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_DEVAD_SHIFT,
+		},
+		.partad = {
+			.mask = MLXBF3_GIGE_MDIO_GW_PARTAD_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_PARTAD_SHIFT,
+		},
+		.opcode = {
+			.mask = MLXBF3_GIGE_MDIO_GW_OPCODE_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_OPCODE_SHIFT,
+		},
+		.st1 = {
+			.mask = MLXBF3_GIGE_MDIO_GW_ST1_MASK,
+			.shift = MLXBF3_GIGE_MDIO_GW_ST1_SHIFT,
+		},
+	},
+};
 
 #define MLXBF_GIGE_MDIO_FREQ_REFERENCE 156250000ULL
 #define MLXBF_GIGE_MDIO_COREPLL_CONST  16384ULL
@@ -47,30 +113,10 @@
 /* Busy bit is set by software and cleared by hardware */
 #define MLXBF_GIGE_MDIO_SET_BUSY	0x1
 
-/* MDIO GW register bits */
-#define MLXBF_GIGE_MDIO_GW_AD_MASK	GENMASK(15, 0)
-#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK	GENMASK(20, 16)
-#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK	GENMASK(25, 21)
-#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK	GENMASK(27, 26)
-#define MLXBF_GIGE_MDIO_GW_ST1_MASK	GENMASK(28, 28)
-#define MLXBF_GIGE_MDIO_GW_BUSY_MASK	GENMASK(30, 30)
-
-/* MDIO config register bits */
-#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK		GENMASK(1, 0)
-#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK		GENMASK(2, 2)
-#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK	GENMASK(4, 4)
-#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK		GENMASK(15, 8)
-#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK		GENMASK(23, 16)
-#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK		GENMASK(31, 24)
-
-#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
-				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
-				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
-				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
-				 FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
-
 #define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30
 #define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c
+#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824
+#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000010
 
 static struct resource corepll_params[] = {
 	[MLXBF_GIGE_VERSION_BF2] = {
@@ -78,6 +124,11 @@ static struct resource corepll_params[] = {
 		.end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1,
 		.name = "COREPLL_RES"
 	},
+	[MLXBF_GIGE_VERSION_BF3] = {
+		.start = MLXBF_GIGE_BF3_COREPLL_ADDR,
+		.end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1,
+		.name = "COREPLL_RES"
+	}
 };
 
 /* Returns core clock i1clk in Hz */
@@ -134,19 +185,23 @@ static u8 mdio_period_map(struct mlxbf_gige *priv)
 	return mdio_period;
 }
 
-static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add,
+static u32 mlxbf_gige_mdio_create_cmd(struct mlxbf_gige_mdio_gw *mdio_gw, u16 data, int phy_add,
 				      int phy_reg, u32 opcode)
 {
 	u32 gw_reg = 0;
 
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data);
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg);
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add);
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode);
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK,
-			     MLXBF_GIGE_MDIO_CL22_ST1);
-	gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK,
-			     MLXBF_GIGE_MDIO_SET_BUSY);
+	gw_reg |= ((data << mdio_gw->write_data.shift) &
+		   mdio_gw->write_data.mask);
+	gw_reg |= ((phy_reg << mdio_gw->devad.shift) &
+		   mdio_gw->devad.mask);
+	gw_reg |= ((phy_add << mdio_gw->partad.shift) &
+		   mdio_gw->partad.mask);
+	gw_reg |= ((opcode << mdio_gw->opcode.shift) &
+		   mdio_gw->opcode.mask);
+	gw_reg |= ((MLXBF_GIGE_MDIO_CL22_ST1 << mdio_gw->st1.shift) &
+		   mdio_gw->st1.mask);
+	gw_reg |= ((MLXBF_GIGE_MDIO_SET_BUSY << mdio_gw->busy.shift) &
+		   mdio_gw->busy.mask);
 
 	return gw_reg;
 }
@@ -162,25 +217,26 @@ static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg)
 		return -EOPNOTSUPP;
 
 	/* Send mdio read request */
-	cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ);
+	cmd = mlxbf_gige_mdio_create_cmd(priv->mdio_gw, 0, phy_add, phy_reg,
+					 MLXBF_GIGE_MDIO_CL22_READ);
 
-	writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+	writel(cmd, priv->mdio_io + priv->mdio_gw->gw_address);
 
-	ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
-					val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK),
+	ret = readl_poll_timeout_atomic(priv->mdio_io + priv->mdio_gw->gw_address,
+					val, !(val & priv->mdio_gw->busy.mask),
 					5, 1000000);
 
 	if (ret) {
-		writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+		writel(0, priv->mdio_io + priv->mdio_gw->gw_address);
 		return ret;
 	}
 
-	ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+	ret = readl(priv->mdio_io + priv->mdio_gw->read_data_address);
 	/* Only return ad bits of the gw register */
-	ret &= MLXBF_GIGE_MDIO_GW_AD_MASK;
+	ret &= priv->mdio_gw->read_data.mask;
 
 	/* The MDIO lock is set on read. To release it, clear gw register */
-	writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+	writel(0, priv->mdio_io + priv->mdio_gw->gw_address);
 
 	return ret;
 }
@@ -197,17 +253,17 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add,
 		return -EOPNOTSUPP;
 
 	/* Send mdio write request */
-	cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg,
+	cmd = mlxbf_gige_mdio_create_cmd(priv->mdio_gw, val, phy_add, phy_reg,
 					 MLXBF_GIGE_MDIO_CL22_WRITE);
-	writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+	writel(cmd, priv->mdio_io + priv->mdio_gw->gw_address);
 
 	/* If the poll timed out, drop the request */
-	ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET,
-					temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK),
+	ret = readl_poll_timeout_atomic(priv->mdio_io + priv->mdio_gw->gw_address,
+					temp, !(temp & priv->mdio_gw->busy.mask),
 					5, 1000000);
 
 	/* The MDIO lock is set on read. To release it, clear gw register */
-	writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET);
+	writel(0, priv->mdio_io + priv->mdio_gw->gw_address);
 
 	return ret;
 }
@@ -219,9 +275,20 @@ static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv)
 
 	mdio_period = mdio_period_map(priv);
 
-	val = MLXBF_GIGE_MDIO_CFG_VAL;
-	val |= FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period);
-	writel(val, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET);
+	if (priv->hw_version == MLXBF_GIGE_VERSION_BF2) {
+		val = MLXBF2_GIGE_MDIO_CFG_VAL;
+		val |= FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period);
+		writel(val, priv->mdio_io + MLXBF2_GIGE_MDIO_CFG_OFFSET);
+	} else {
+		val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) |
+		      FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1);
+		writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG0);
+		val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdio_period);
+		writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG1);
+		val = FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) |
+		      FIELD_PREP(MLXBF3_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13);
+		writel(val, priv->mdio_io + MLXBF3_GIGE_MDIO_CFG_REG2);
+	}
 }
 
 int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
@@ -230,6 +297,9 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
 	struct resource *res;
 	int ret;
 
+	if (priv->hw_version > MLXBF_GIGE_VERSION_BF3)
+		return -ENODEV;
+
 	priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9);
 	if (IS_ERR(priv->mdio_io))
 		return PTR_ERR(priv->mdio_io);
@@ -242,13 +312,15 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
 		/* For backward compatibility with older ACPI tables, also keep
 		 * CLK resource internal to the driver.
 		 */
-		res = &corepll_params[MLXBF_GIGE_VERSION_BF2];
+		res = &corepll_params[priv->hw_version];
 	}
 
 	priv->clk_io = devm_ioremap(dev, res->start, resource_size(res));
 	if (!priv->clk_io)
 		return -ENOMEM;
 
+	priv->mdio_gw = &mlxbf_gige_mdio_gw_t[priv->hw_version];
+
 	mlxbf_gige_mdio_cfg(priv);
 
 	priv->mdiobus = devm_mdiobus_alloc(dev);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h
new file mode 100644
index 000000000000..7f1ff0ac7699
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf2.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+
+/* MDIO support for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES, ALL RIGHTS RESERVED.
+ *
+ * This software product is a proprietary product of NVIDIA CORPORATION &
+ * AFFILIATES (the "Company") and all right, title, and interest in and to the
+ * software product, including all associated intellectual property rights, are
+ * and shall remain exclusively with the Company.
+ *
+ * This software product is governed by the End User License Agreement
+ * provided with the software product.
+ */
+
+#ifndef __MLXBF_GIGE_MDIO_BF2_H__
+#define __MLXBF_GIGE_MDIO_BF2_H__
+
+#include <linux/bitfield.h>
+
+#define MLXBF2_GIGE_MDIO_GW_OFFSET	0x0
+#define MLXBF2_GIGE_MDIO_CFG_OFFSET	0x4
+
+/* MDIO GW register bits */
+#define MLXBF2_GIGE_MDIO_GW_AD_MASK	GENMASK(15, 0)
+#define MLXBF2_GIGE_MDIO_GW_DEVAD_MASK	GENMASK(20, 16)
+#define MLXBF2_GIGE_MDIO_GW_PARTAD_MASK	GENMASK(25, 21)
+#define MLXBF2_GIGE_MDIO_GW_OPCODE_MASK	GENMASK(27, 26)
+#define MLXBF2_GIGE_MDIO_GW_ST1_MASK	GENMASK(28, 28)
+#define MLXBF2_GIGE_MDIO_GW_BUSY_MASK	GENMASK(30, 30)
+
+#define MLXBF2_GIGE_MDIO_GW_AD_SHIFT     0
+#define MLXBF2_GIGE_MDIO_GW_DEVAD_SHIFT  16
+#define MLXBF2_GIGE_MDIO_GW_PARTAD_SHIFT 21
+#define MLXBF2_GIGE_MDIO_GW_OPCODE_SHIFT 26
+#define MLXBF2_GIGE_MDIO_GW_ST1_SHIFT    28
+#define MLXBF2_GIGE_MDIO_GW_BUSY_SHIFT   30
+
+/* MDIO config register bits */
+#define MLXBF2_GIGE_MDIO_CFG_MDIO_MODE_MASK		GENMASK(1, 0)
+#define MLXBF2_GIGE_MDIO_CFG_MDIO3_3_MASK		GENMASK(2, 2)
+#define MLXBF2_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK	GENMASK(4, 4)
+#define MLXBF2_GIGE_MDIO_CFG_MDC_PERIOD_MASK		GENMASK(15, 8)
+#define MLXBF2_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK		GENMASK(23, 16)
+#define MLXBF2_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK		GENMASK(31, 24)
+
+#define MLXBF2_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \
+				 FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \
+				 FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \
+				 FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \
+				 FIELD_PREP(MLXBF2_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13))
+
+#endif /* __MLXBF_GIGE_MDIO_BF2_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h
new file mode 100644
index 000000000000..9dd9144b9173
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio_bf3.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+
+/* MDIO support for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES, ALL RIGHTS RESERVED.
+ *
+ * This software product is a proprietary product of NVIDIA CORPORATION &
+ * AFFILIATES (the "Company") and all right, title, and interest in and to the
+ * software product, including all associated intellectual property rights, are
+ * and shall remain exclusively with the Company.
+ *
+ * This software product is governed by the End User License Agreement
+ * provided with the software product.
+ */
+
+#ifndef __MLXBF_GIGE_MDIO_BF3_H__
+#define __MLXBF_GIGE_MDIO_BF3_H__
+
+#include <linux/bitfield.h>
+
+#define MLXBF3_GIGE_MDIO_GW_OFFSET	0x80
+#define MLXBF3_GIGE_MDIO_DATA_READ	0x8c
+#define MLXBF3_GIGE_MDIO_CFG_REG0	0x100
+#define MLXBF3_GIGE_MDIO_CFG_REG1	0x104
+#define MLXBF3_GIGE_MDIO_CFG_REG2	0x108
+
+/* MDIO GW register bits */
+#define MLXBF3_GIGE_MDIO_GW_ST1_MASK	GENMASK(1, 1)
+#define MLXBF3_GIGE_MDIO_GW_OPCODE_MASK	GENMASK(3, 2)
+#define MLXBF3_GIGE_MDIO_GW_PARTAD_MASK	GENMASK(8, 4)
+#define MLXBF3_GIGE_MDIO_GW_DEVAD_MASK	GENMASK(13, 9)
+/* For BlueField-3, this field is only used for mdio write */
+#define MLXBF3_GIGE_MDIO_GW_DATA_MASK	GENMASK(29, 14)
+#define MLXBF3_GIGE_MDIO_GW_BUSY_MASK	GENMASK(30, 30)
+
+#define MLXBF3_GIGE_MDIO_GW_DATA_READ_MASK GENMASK(15, 0)
+
+#define MLXBF3_GIGE_MDIO_GW_ST1_SHIFT    1
+#define MLXBF3_GIGE_MDIO_GW_OPCODE_SHIFT 2
+#define MLXBF3_GIGE_MDIO_GW_PARTAD_SHIFT 4
+#define MLXBF3_GIGE_MDIO_GW_DEVAD_SHIFT	 9
+#define MLXBF3_GIGE_MDIO_GW_DATA_SHIFT   14
+#define MLXBF3_GIGE_MDIO_GW_BUSY_SHIFT   30
+
+#define MLXBF3_GIGE_MDIO_GW_DATA_READ_SHIFT 0
+
+/* MDIO config register bits */
+#define MLXBF3_GIGE_MDIO_CFG_MDIO_MODE_MASK		GENMASK(1, 0)
+#define MLXBF3_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK	GENMASK(2, 2)
+#define MLXBF3_GIGE_MDIO_CFG_MDC_PERIOD_MASK		GENMASK(7, 0)
+#define MLXBF3_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK		GENMASK(7, 0)
+#define MLXBF3_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK		GENMASK(15, 8)
+
+#endif /* __MLXBF_GIGE_MDIO_BF3_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
index 7be3a793984d..8d52dbef4adf 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
@@ -10,6 +10,7 @@
 
 #define MLXBF_GIGE_VERSION                            0x0000
 #define MLXBF_GIGE_VERSION_BF2                        0x0
+#define MLXBF_GIGE_VERSION_BF3                        0x1
 #define MLXBF_GIGE_STATUS                             0x0010
 #define MLXBF_GIGE_STATUS_READY                       BIT(0)
 #define MLXBF_GIGE_INT_STATUS                         0x0028
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3
  2022-11-09 22:47 [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support David Thompson
  2022-11-09 22:47 ` [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3 David Thompson
@ 2022-11-09 22:47 ` David Thompson
  2022-11-10 13:23   ` Andrew Lunn
  2022-11-09 22:47 ` [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration David Thompson
  2022-11-09 22:47 ` [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback David Thompson
  3 siblings, 1 reply; 19+ messages in thread
From: David Thompson @ 2022-11-09 22:47 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: netdev, cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	David Thompson, Asmaa Mnebhi

The BlueField-3 OOB interface supports 10Mbps, 100Mbps, and 1Gbps speeds.
The external PHY is responsible for autonegotiating the speed with the
link partner. Once the autonegotiation is done, the BlueField PLU needs
to be configured accordingly.

This patch does two things:
1) Initialize the advertised control flow/duplex/speed in the probe
   based on the BlueField SoC generation (2 or 3)
2) Adjust the PLU speed config in the PHY interrupt handler

Signed-off-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
---
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |   8 ++
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     | 105 +++++++++++++++---
 .../mellanox/mlxbf_gige/mlxbf_gige_regs.h     |  21 ++++
 3 files changed, 119 insertions(+), 15 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index 421a0b1b766c..a453b9cd9033 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -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 */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index e08c07e914c1..32d7030eb2cf 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -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);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
index 8d52dbef4adf..cd0973229c9b 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h
@@ -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__) */
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-09 22:47 [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support David Thompson
  2022-11-09 22:47 ` [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3 David Thompson
  2022-11-09 22:47 ` [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3 David Thompson
@ 2022-11-09 22:47 ` David Thompson
  2022-11-10 13:33   ` Andrew Lunn
  2022-11-09 22:47 ` [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback David Thompson
  3 siblings, 1 reply; 19+ messages in thread
From: David Thompson @ 2022-11-09 22:47 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: netdev, cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	David Thompson, Asmaa Mnebhi

The BlueField-3 out-of-band Ethernet interface requires
SerDes configuration. There are two aspects to this:

Configuration of PLL:
    1) Initialize UPHY registers to values dependent on p1clk clock
    2) Load PLL best known values via the gateway register
    3) Set the fuses to tune up the SerDes voltage
    4) Lock the PLL
    5) Get the lanes out of functional reset.
    6) Configure the UPHY microcontroller via gateway reads/writes

Configuration of lanes:
    1) Configure and open TX lanes
    2) Configure and open RX lanes

Signed-off-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
---
 .../net/ethernet/mellanox/mlxbf_gige/Makefile |    3 +-
 .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h |    4 +-
 .../mellanox/mlxbf_gige/mlxbf_gige_main.c     |   57 +-
 .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c     |   37 -
 .../mellanox/mlxbf_gige/mlxbf_gige_uphy.c     | 1173 +++++++++++++++++
 .../mellanox/mlxbf_gige/mlxbf_gige_uphy.h     |  398 ++++++
 6 files changed, 1628 insertions(+), 44 deletions(-)
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c
 create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
index a97c2bef846b..524af17cad9c 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile
@@ -7,4 +7,5 @@ mlxbf_gige-y := mlxbf_gige_ethtool.o \
 		mlxbf_gige_main.o \
 		mlxbf_gige_mdio.o \
 		mlxbf_gige_rx.o   \
-		mlxbf_gige_tx.o
+		mlxbf_gige_tx.o   \
+		mlxbf_gige_uphy.o
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
index a453b9cd9033..e9bd09ee0b1f 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h
@@ -100,6 +100,7 @@ struct mlxbf_gige {
 	struct platform_device *pdev;
 	void __iomem *mdio_io;
 	void __iomem *clk_io;
+	void __iomem *fuse_gw_io;
 	struct mii_bus *mdiobus;
 	spinlock_t lock;      /* for packet processing indices */
 	u16 rx_q_entries;
@@ -166,7 +167,8 @@ enum mlxbf_gige_res {
 	MLXBF_GIGE_RES_GPIO0,
 	MLXBF_GIGE_RES_LLU,
 	MLXBF_GIGE_RES_PLU,
-	MLXBF_GIGE_RES_CLK
+	MLXBF_GIGE_RES_CLK,
+	MLXBF_GIGE_RES_FUSE_GW
 };
 
 /* Version of register data returned by mlxbf_gige_get_regs() */
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index 32d7030eb2cf..80060a54ba95 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -18,6 +18,25 @@
 
 #include "mlxbf_gige.h"
 #include "mlxbf_gige_regs.h"
+#include "mlxbf_gige_uphy.h"
+
+#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30
+#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c
+#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824
+#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000020
+
+static struct resource corepll_params[] = {
+	[MLXBF_GIGE_VERSION_BF2] = {
+		.start = MLXBF_GIGE_BF2_COREPLL_ADDR,
+		.end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1,
+		.name = "COREPLL_RES"
+	},
+	[MLXBF_GIGE_VERSION_BF3] = {
+		.start = MLXBF_GIGE_BF3_COREPLL_ADDR,
+		.end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1,
+		.name = "COREPLL_RES"
+	}
+};
 
 /* Allocate SKB whose payload pointer aligns with the Bluefield
  * hardware DMA limitation, i.e. DMA operation can't cross
@@ -360,11 +379,14 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
 {
 	struct phy_device *phydev;
 	struct net_device *netdev;
+	struct resource *clk_res;
 	struct mlxbf_gige *priv;
 	void __iomem *llu_base;
 	void __iomem *plu_base;
+	void __iomem *clk_io;
 	void __iomem *base;
 	int addr, phy_irq;
+	u64 soc_version;
 	u64 control;
 	int err;
 
@@ -372,6 +394,25 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
+	soc_version = readq(base + MLXBF_GIGE_VERSION);
+	if (soc_version > MLXBF_GIGE_VERSION_BF3)
+		return -ENODEV;
+
+	/* clk resource shared with other drivers so cannot use
+	 * devm_platform_ioremap_resource
+	 */
+	clk_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK);
+	if (!clk_res) {
+		/* For backward compatibility with older ACPI tables, also keep
+		 * CLK resource internal to the driver.
+		 */
+		clk_res = &corepll_params[soc_version];
+	}
+
+	clk_io = devm_ioremap(&pdev->dev, clk_res->start, resource_size(clk_res));
+	if (!clk_io)
+		return -ENOMEM;
+
 	llu_base = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_LLU);
 	if (IS_ERR(llu_base))
 		return PTR_ERR(llu_base);
@@ -401,17 +442,23 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
 
 	spin_lock_init(&priv->lock);
 
-	priv->hw_version = readq(base + MLXBF_GIGE_VERSION);
+	priv->clk_io = clk_io;
+	priv->base = base;
+	priv->llu_base = llu_base;
+	priv->plu_base = plu_base;
+	priv->hw_version = soc_version;
+
+	if (priv->hw_version == MLXBF_GIGE_VERSION_BF3) {
+		err = mlxbf_gige_config_uphy(priv);
+		if (err)
+			return err;
+	}
 
 	/* Attach MDIO device */
 	err = mlxbf_gige_mdio_probe(pdev, priv);
 	if (err)
 		return err;
 
-	priv->base = base;
-	priv->llu_base = llu_base;
-	priv->plu_base = plu_base;
-
 	priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ;
 	priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ;
 
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
index 7ac06fd31011..043edf57e36b 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c
@@ -113,24 +113,6 @@ static struct mlxbf_gige_mdio_gw mlxbf_gige_mdio_gw_t[] = {
 /* Busy bit is set by software and cleared by hardware */
 #define MLXBF_GIGE_MDIO_SET_BUSY	0x1
 
-#define MLXBF_GIGE_BF2_COREPLL_ADDR 0x02800c30
-#define MLXBF_GIGE_BF2_COREPLL_SIZE 0x0000000c
-#define MLXBF_GIGE_BF3_COREPLL_ADDR 0x13409824
-#define MLXBF_GIGE_BF3_COREPLL_SIZE 0x00000010
-
-static struct resource corepll_params[] = {
-	[MLXBF_GIGE_VERSION_BF2] = {
-		.start = MLXBF_GIGE_BF2_COREPLL_ADDR,
-		.end = MLXBF_GIGE_BF2_COREPLL_ADDR + MLXBF_GIGE_BF2_COREPLL_SIZE - 1,
-		.name = "COREPLL_RES"
-	},
-	[MLXBF_GIGE_VERSION_BF3] = {
-		.start = MLXBF_GIGE_BF3_COREPLL_ADDR,
-		.end = MLXBF_GIGE_BF3_COREPLL_ADDR + MLXBF_GIGE_BF3_COREPLL_SIZE - 1,
-		.name = "COREPLL_RES"
-	}
-};
-
 /* Returns core clock i1clk in Hz */
 static u64 calculate_i1clk(struct mlxbf_gige *priv)
 {
@@ -294,31 +276,12 @@ static void mlxbf_gige_mdio_cfg(struct mlxbf_gige *priv)
 int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv)
 {
 	struct device *dev = &pdev->dev;
-	struct resource *res;
 	int ret;
 
-	if (priv->hw_version > MLXBF_GIGE_VERSION_BF3)
-		return -ENODEV;
-
 	priv->mdio_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MDIO9);
 	if (IS_ERR(priv->mdio_io))
 		return PTR_ERR(priv->mdio_io);
 
-	/* clk resource shared with other drivers so cannot use
-	 * devm_platform_ioremap_resource
-	 */
-	res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_CLK);
-	if (!res) {
-		/* For backward compatibility with older ACPI tables, also keep
-		 * CLK resource internal to the driver.
-		 */
-		res = &corepll_params[priv->hw_version];
-	}
-
-	priv->clk_io = devm_ioremap(dev, res->start, resource_size(res));
-	if (!priv->clk_io)
-		return -ENOMEM;
-
 	priv->mdio_gw = &mlxbf_gige_mdio_gw_t[priv->hw_version];
 
 	mlxbf_gige_mdio_cfg(priv);
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c
new file mode 100644
index 000000000000..eb8c55b135a9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.c
@@ -0,0 +1,1173 @@
+// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+
+/* UPHY support for Nvidia Gigabit Ethernet driver
+ *
+ * Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+#include <linux/platform_device.h>
+
+#include "mlxbf_gige.h"
+#include "mlxbf_gige_uphy.h"
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_clm_init[] = {
+	{.addr = 0x001, .wdata = 0x0105},
+	{.addr = 0x008, .wdata = 0x0001},
+	{.addr = 0x00B, .wdata = 0x8420},
+	{.addr = 0x00E, .wdata = 0x0110},
+	{.addr = 0x010, .wdata = 0x3010},
+	{.addr = 0x027, .wdata = 0x0104},
+	{.addr = 0x02F, .wdata = 0x09EA},
+	{.addr = 0x055, .wdata = 0x0008},
+	{.addr = 0x058, .wdata = 0x0088},
+	{.addr = 0x072, .wdata = 0x3222},
+	{.addr = 0x073, .wdata = 0x7654},
+	{.addr = 0x074, .wdata = 0xBA98},
+	{.addr = 0x075, .wdata = 0xDDDC}
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_imem_init[] = {
+	{.addr = 0x39C, .wdata = 0x0000},
+	{.addr = 0x39D, .wdata = 0x0095},
+	{.addr = 0x3BF, .wdata = 0x9027},
+	{.addr = 0x39E, .wdata = 0xA8F6},
+	{.addr = 0x39F, .wdata = 0xAA10},
+	{.addr = 0x3A0, .wdata = 0xA8D4},
+	{.addr = 0x3A1, .wdata = 0xA7AE},
+	{.addr = 0x3A2, .wdata = 0xA7CC},
+	{.addr = 0x3A3, .wdata = 0x9BE4},
+	{.addr = 0x3A4, .wdata = 0xB2D2},
+	{.addr = 0x3A5, .wdata = 0xB1F2},
+	{.addr = 0x3AE, .wdata = 0x7C38},
+	{.addr = 0x3AF, .wdata = 0x7C4A},
+	{.addr = 0x3B0, .wdata = 0x7C25},
+	{.addr = 0x3B1, .wdata = 0x7C74},
+	{.addr = 0x3B2, .wdata = 0x3C00},
+	{.addr = 0x3B3, .wdata = 0x3C11},
+	{.addr = 0x3B4, .wdata = 0x3C5D},
+	{.addr = 0x3B5, .wdata = 0x3C5D}
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_seq_imem_wr_en_init = {
+	.addr = 0x39A, .wdata = 0x0001
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_seq_imem_wr_dis_init = {
+	.addr = 0x39A, .wdata = 0x0000
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_imem_data[] = {
+	{ /* .iaddr = 0x0000 */ .wdata = 0x02DF},
+	{ /* .iaddr = 0x0001 */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x0002 */ .wdata = 0xD508},
+	{ /* .iaddr = 0x0003 */ .wdata = 0x022F},
+	{ /* .iaddr = 0x0004 */ .wdata = 0xC401},
+	{ /* .iaddr = 0x0005 */ .wdata = 0xD341},
+	{ /* .iaddr = 0x0006 */ .wdata = 0xC402},
+	{ /* .iaddr = 0x0007 */ .wdata = 0xD342},
+	{ /* .iaddr = 0x0008 */ .wdata = 0xC403},
+	{ /* .iaddr = 0x0009 */ .wdata = 0xD343},
+	{ /* .iaddr = 0x000A */ .wdata = 0xC404},
+	{ /* .iaddr = 0x000B */ .wdata = 0xD344},
+	{ /* .iaddr = 0x000C */ .wdata = 0xC417},
+	{ /* .iaddr = 0x000D */ .wdata = 0xD355},
+	{ /* .iaddr = 0x000E */ .wdata = 0xC418},
+	{ /* .iaddr = 0x000F */ .wdata = 0xD356},
+	{ /* .iaddr = 0x0010 */ .wdata = 0xF021},
+	{ /* .iaddr = 0x0011 */ .wdata = 0xF003},
+	{ /* .iaddr = 0x0012 */ .wdata = 0xE224},
+	{ /* .iaddr = 0x0013 */ .wdata = 0x0DA9},
+	{ /* .iaddr = 0x0014 */ .wdata = 0xF003},
+	{ /* .iaddr = 0x0015 */ .wdata = 0xE21C},
+	{ /* .iaddr = 0x0016 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0017 */ .wdata = 0x0D87},
+	{ /* .iaddr = 0x0018 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0019 */ .wdata = 0xE806},
+	{ /* .iaddr = 0x001A */ .wdata = 0xC3C5},
+	{ /* .iaddr = 0x001B */ .wdata = 0xD306},
+	{ /* .iaddr = 0x001C */ .wdata = 0xEEDF},
+	{ /* .iaddr = 0x001D */ .wdata = 0xE806},
+	{ /* .iaddr = 0x001E */ .wdata = 0xC3C6},
+	{ /* .iaddr = 0x001F */ .wdata = 0xD306},
+	{ /* .iaddr = 0x0020 */ .wdata = 0xF002},
+	{ /* .iaddr = 0x0021 */ .wdata = 0xC3C8},
+	{ /* .iaddr = 0x0022 */ .wdata = 0x409A},
+	{ /* .iaddr = 0x0023 */ .wdata = 0xF021},
+	{ /* .iaddr = 0x0024 */ .wdata = 0xEEE0},
+	{ /* .iaddr = 0x0025 */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x0026 */ .wdata = 0xD70D},
+	{ /* .iaddr = 0x0027 */ .wdata = 0xC305},
+	{ /* .iaddr = 0x0028 */ .wdata = 0xD328},
+	{ /* .iaddr = 0x0029 */ .wdata = 0xC300},
+	{ /* .iaddr = 0x002A */ .wdata = 0xD314},
+	{ /* .iaddr = 0x002B */ .wdata = 0xC301},
+	{ /* .iaddr = 0x002C */ .wdata = 0xD318},
+	{ /* .iaddr = 0x002D */ .wdata = 0xC303},
+	{ /* .iaddr = 0x002E */ .wdata = 0xD320},
+	{ /* .iaddr = 0x002F */ .wdata = 0xC302},
+	{ /* .iaddr = 0x0030 */ .wdata = 0xD31C},
+	{ /* .iaddr = 0x0031 */ .wdata = 0xC304},
+	{ /* .iaddr = 0x0032 */ .wdata = 0xD324},
+	{ /* .iaddr = 0x0033 */ .wdata = 0xC358},
+	{ /* .iaddr = 0x0034 */ .wdata = 0xD330},
+	{ /* .iaddr = 0x0035 */ .wdata = 0xC307},
+	{ /* .iaddr = 0x0036 */ .wdata = 0xD115},
+	{ /* .iaddr = 0x0037 */ .wdata = 0xF021},
+	{ /* .iaddr = 0x0038 */ .wdata = 0xD70D},
+	{ /* .iaddr = 0x0039 */ .wdata = 0xC305},
+	{ /* .iaddr = 0x003A */ .wdata = 0xD328},
+	{ /* .iaddr = 0x003B */ .wdata = 0xC300},
+	{ /* .iaddr = 0x003C */ .wdata = 0xD314},
+	{ /* .iaddr = 0x003D */ .wdata = 0xC301},
+	{ /* .iaddr = 0x003E */ .wdata = 0xD318},
+	{ /* .iaddr = 0x003F */ .wdata = 0xC303},
+	{ /* .iaddr = 0x0040 */ .wdata = 0xD320},
+	{ /* .iaddr = 0x0041 */ .wdata = 0xC302},
+	{ /* .iaddr = 0x0042 */ .wdata = 0xD31C},
+	{ /* .iaddr = 0x0043 */ .wdata = 0xC304},
+	{ /* .iaddr = 0x0044 */ .wdata = 0xD324},
+	{ /* .iaddr = 0x0045 */ .wdata = 0xC358},
+	{ /* .iaddr = 0x0046 */ .wdata = 0xD330},
+	{ /* .iaddr = 0x0047 */ .wdata = 0xC307},
+	{ /* .iaddr = 0x0048 */ .wdata = 0xD115},
+	{ /* .iaddr = 0x0049 */ .wdata = 0xF021},
+	{ /* .iaddr = 0x004A */ .wdata = 0xC70D},
+	{ /* .iaddr = 0x004B */ .wdata = 0xD70F},
+	{ /* .iaddr = 0x004C */ .wdata = 0xC328},
+	{ /* .iaddr = 0x004D */ .wdata = 0xD305},
+	{ /* .iaddr = 0x004E */ .wdata = 0xC314},
+	{ /* .iaddr = 0x004F */ .wdata = 0xD300},
+	{ /* .iaddr = 0x0050 */ .wdata = 0xC318},
+	{ /* .iaddr = 0x0051 */ .wdata = 0xD301},
+	{ /* .iaddr = 0x0052 */ .wdata = 0xC320},
+	{ /* .iaddr = 0x0053 */ .wdata = 0xD303},
+	{ /* .iaddr = 0x0054 */ .wdata = 0xC31C},
+	{ /* .iaddr = 0x0055 */ .wdata = 0xD302},
+	{ /* .iaddr = 0x0056 */ .wdata = 0xC324},
+	{ /* .iaddr = 0x0057 */ .wdata = 0xD304},
+	{ /* .iaddr = 0x0058 */ .wdata = 0xC330},
+	{ /* .iaddr = 0x0059 */ .wdata = 0xD358},
+	{ /* .iaddr = 0x005A */ .wdata = 0xC115},
+	{ /* .iaddr = 0x005B */ .wdata = 0xD307},
+	{ /* .iaddr = 0x005C */ .wdata = 0xF021},
+	{ /* .iaddr = 0x005D */ .wdata = 0x0249},
+	{ /* .iaddr = 0x005E */ .wdata = 0x0362},
+	{ /* .iaddr = 0x005F */ .wdata = 0x023D},
+	{ /* .iaddr = 0x0060 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0061 */ .wdata = 0x0369},
+	{ /* .iaddr = 0x0062 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0063 */ .wdata = 0x0CEA},
+	{ /* .iaddr = 0x0064 */ .wdata = 0xEEC2},
+	{ /* .iaddr = 0x0065 */ .wdata = 0xD701},
+	{ /* .iaddr = 0x0066 */ .wdata = 0x02C8},
+	{ /* .iaddr = 0x0067 */ .wdata = 0xC3C3},
+	{ /* .iaddr = 0x0068 */ .wdata = 0xD306},
+	{ /* .iaddr = 0x0069 */ .wdata = 0xC3C8},
+	{ /* .iaddr = 0x006A */ .wdata = 0x009A},
+	{ /* .iaddr = 0x006B */ .wdata = 0xC3D1},
+	{ /* .iaddr = 0x006C */ .wdata = 0xD309},
+	{ /* .iaddr = 0x006D */ .wdata = 0x0C46},
+	{ /* .iaddr = 0x006E */ .wdata = 0x0DE7},
+	{ /* .iaddr = 0x006F */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x0070 */ .wdata = 0xC3D9},
+	{ /* .iaddr = 0x0071 */ .wdata = 0x0DDE},
+	{ /* .iaddr = 0x0072 */ .wdata = 0x02D7},
+	{ /* .iaddr = 0x0073 */ .wdata = 0xF021},
+	{ /* .iaddr = 0x0074 */ .wdata = 0x1441},
+	{ /* .iaddr = 0x0075 */ .wdata = 0xF003},
+	{ /* .iaddr = 0x0076 */ .wdata = 0xC03F},
+	{ /* .iaddr = 0x0077 */ .wdata = 0xF704},
+	{ /* .iaddr = 0x0078 */ .wdata = 0xF009},
+	{ /* .iaddr = 0x0079 */ .wdata = 0xE21A},
+	{ /* .iaddr = 0x007A */ .wdata = 0xF002},
+	{ /* .iaddr = 0x007B */ .wdata = 0x0C52},
+	{ /* .iaddr = 0x007C */ .wdata = 0xE206},
+	{ /* .iaddr = 0x007D */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x007E */ .wdata = 0xD01A},
+	{ /* .iaddr = 0x007F */ .wdata = 0x3C5D},
+	{ /* .iaddr = 0x0080 */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x0081 */ .wdata = 0xD01A},
+	{ /* .iaddr = 0x0082 */ .wdata = 0x0E12},
+	{ /* .iaddr = 0x0083 */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x0084 */ .wdata = 0x13E1},
+	{ /* .iaddr = 0x0085 */ .wdata = 0x1441},
+	{ /* .iaddr = 0x0086 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0087 */ .wdata = 0xD70E},
+	{ /* .iaddr = 0x0088 */ .wdata = 0xD70F},
+	{ /* .iaddr = 0x0089 */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x008A */ .wdata = 0xD70E},
+	{ /* .iaddr = 0x008B */ .wdata = 0xC458},
+	{ /* .iaddr = 0x008C */ .wdata = 0x13BE},
+	{ /* .iaddr = 0x008D */ .wdata = 0xEEC0},
+	{ /* .iaddr = 0x008E */ .wdata = 0xF29B},
+	{ /* .iaddr = 0x008F */ .wdata = 0xE20A},
+	{ /* .iaddr = 0x0090 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0091 */ .wdata = 0xD01D},
+	{ /* .iaddr = 0x0092 */ .wdata = 0xEEC1},
+	{ /* .iaddr = 0x0093 */ .wdata = 0xD3FD},
+	{ /* .iaddr = 0x0094 */ .wdata = 0xF021}
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_seq_imem_csum_en = {
+	.addr = 0x39A, .wdata = 0x0004
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_seq_imem_csum_dis = {
+	.addr = 0x39A, .wdata = 0x0000
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_seq_imem_bmap_clr[] = {
+	{.addr = 0x39E, .wdata = 0x0000},
+	{.addr = 0x39F, .wdata = 0x0000},
+	{.addr = 0x3A0, .wdata = 0x0000},
+	{.addr = 0x3A1, .wdata = 0x0000},
+	{.addr = 0x3A2, .wdata = 0x0000},
+	{.addr = 0x3A3, .wdata = 0x0000},
+	{.addr = 0x3A4, .wdata = 0x0000},
+	{.addr = 0x3A5, .wdata = 0x0000},
+	{.addr = 0x3A6, .wdata = 0x0000},
+	{.addr = 0x3A7, .wdata = 0x0000},
+	{.addr = 0x3A8, .wdata = 0x0000},
+	{.addr = 0x3A9, .wdata = 0x0000},
+	{.addr = 0x3AA, .wdata = 0x0000},
+	{.addr = 0x3AB, .wdata = 0x0000},
+	{.addr = 0x3AC, .wdata = 0x0000},
+	{.addr = 0x3AD, .wdata = 0x0000},
+	{.addr = 0x3AE, .wdata = 0x0000},
+	{.addr = 0x3AF, .wdata = 0x0000},
+	{.addr = 0x3B0, .wdata = 0x0000},
+	{.addr = 0x3B1, .wdata = 0x0000},
+	{.addr = 0x3B2, .wdata = 0x0000},
+	{.addr = 0x3B3, .wdata = 0x0000},
+	{.addr = 0x3B4, .wdata = 0x0000},
+	{.addr = 0x3B5, .wdata = 0x0000},
+	{.addr = 0x3B6, .wdata = 0x0000},
+	{.addr = 0x3B7, .wdata = 0x0000},
+	{.addr = 0x3B8, .wdata = 0x0000},
+	{.addr = 0x3B9, .wdata = 0x0000},
+	{.addr = 0x3BA, .wdata = 0x0000},
+	{.addr = 0x3BB, .wdata = 0x0000},
+	{.addr = 0x3BC, .wdata = 0x0000},
+	{.addr = 0x3BD, .wdata = 0x0000}
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_tx_init[] = {
+	{.addr = 0x002, .wdata = 0x5125},
+	{.addr = 0x01C, .wdata = 0x0018},
+	{.addr = 0x01E, .wdata = 0x0E00},
+	{.addr = 0x01F, .wdata = 0xC200},
+	{.addr = 0x023, .wdata = 0x0277},
+	{.addr = 0x024, .wdata = 0x026B},
+	{.addr = 0x053, .wdata = 0x0700},
+	{.addr = 0x059, .wdata = 0x1011},
+	{.addr = 0x060, .wdata = 0x0000},
+	{.addr = 0x062, .wdata = 0x0135},
+	{.addr = 0x063, .wdata = 0x0443},
+	{.addr = 0x064, .wdata = 0x0000},
+	{.addr = 0x066, .wdata = 0x0061},
+	{.addr = 0x067, .wdata = 0x0042},
+	{.addr = 0x06A, .wdata = 0x1212},
+	{.addr = 0x06B, .wdata = 0x1515},
+	{.addr = 0x06C, .wdata = 0x011A},
+	{.addr = 0x06D, .wdata = 0x0132},
+	{.addr = 0x06E, .wdata = 0x0632},
+	{.addr = 0x06F, .wdata = 0x0643},
+	{.addr = 0x070, .wdata = 0x0233},
+	{.addr = 0x071, .wdata = 0x0433},
+	{.addr = 0x07E, .wdata = 0x6A08},
+	{.addr = 0x08D, .wdata = 0x2101},
+	{.addr = 0x093, .wdata = 0x0015},
+	{.addr = 0x096, .wdata = 0x7555},
+	{.addr = 0x0A9, .wdata = 0xE754},
+	{.addr = 0x0AA, .wdata = 0x7ED1},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000}
+};
+
+static const struct mlxbf_gige_uphy_cfg_reg
+mlxbf_gige_dlm_rx_init[] = {
+	{.addr = 0x003, .wdata = 0x5125},
+	{.addr = 0x01D, .wdata = 0x0004},
+	{.addr = 0x028, .wdata = 0x1000},
+	{.addr = 0x029, .wdata = 0x1001},
+	{.addr = 0x02E, .wdata = 0x0004},
+	{.addr = 0x053, .wdata = 0x0700},
+	{.addr = 0x057, .wdata = 0x5044},
+	{.addr = 0x05B, .wdata = 0x1011},
+	{.addr = 0x0D2, .wdata = 0x0002},
+	{.addr = 0x0D9, .wdata = 0x0000},
+	{.addr = 0x0DA, .wdata = 0x0000},
+	{.addr = 0x0DB, .wdata = 0x0000},
+	{.addr = 0x0E2, .wdata = 0x0000},
+	{.addr = 0x0E7, .wdata = 0xBB10},
+	{.addr = 0x0E8, .wdata = 0xBB10},
+	{.addr = 0x0EC, .wdata = 0x0111},
+	{.addr = 0x0ED, .wdata = 0x1C00},
+	{.addr = 0x0F5, .wdata = 0x0000},
+	{.addr = 0x102, .wdata = 0x0CA6},
+	{.addr = 0x107, .wdata = 0x0020},
+	{.addr = 0x10C, .wdata = 0x1E31},
+	{.addr = 0x10D, .wdata = 0x1D29},
+	{.addr = 0x111, .wdata = 0x00E7},
+	{.addr = 0x112, .wdata = 0x5202},
+	{.addr = 0x117, .wdata = 0x0493},
+	{.addr = 0x11B, .wdata = 0x0148},
+	{.addr = 0x120, .wdata = 0x23DE},
+	{.addr = 0x121, .wdata = 0x2294},
+	{.addr = 0x125, .wdata = 0x03FF},
+	{.addr = 0x126, .wdata = 0x25F0},
+	{.addr = 0x12B, .wdata = 0xC633},
+	{.addr = 0x136, .wdata = 0x0F6A},
+	{.addr = 0x143, .wdata = 0x0000},
+	{.addr = 0x148, .wdata = 0x0001},
+	{.addr = 0x14E, .wdata = 0x0000},
+	{.addr = 0x155, .wdata = 0x2003},
+	{.addr = 0x15C, .wdata = 0x099B},
+	{.addr = 0x161, .wdata = 0x0088},
+	{.addr = 0x16B, .wdata = 0x0433},
+	{.addr = 0x172, .wdata = 0x099B},
+	{.addr = 0x17C, .wdata = 0x045D},
+	{.addr = 0x17D, .wdata = 0x006A},
+	{.addr = 0x181, .wdata = 0x0000},
+	{.addr = 0x189, .wdata = 0x1590},
+	{.addr = 0x18E, .wdata = 0x0080},
+	{.addr = 0x18F, .wdata = 0x90EC},
+	{.addr = 0x191, .wdata = 0x79F8},
+	{.addr = 0x194, .wdata = 0x000A},
+	{.addr = 0x195, .wdata = 0x000A},
+	{.addr = 0x1EB, .wdata = 0x0133},
+	{.addr = 0x1F0, .wdata = 0x0030},
+	{.addr = 0x1F1, .wdata = 0x0030},
+	{.addr = 0x1F5, .wdata = 0x3737},
+	{.addr = 0x1F6, .wdata = 0x3737},
+	{.addr = 0x1FA, .wdata = 0x2C00},
+	{.addr = 0x1FF, .wdata = 0x0516},
+	{.addr = 0x200, .wdata = 0x0516},
+	{.addr = 0x204, .wdata = 0x3010},
+	{.addr = 0x209, .wdata = 0x0429},
+	{.addr = 0x20E, .wdata = 0x0010},
+	{.addr = 0x213, .wdata = 0x005A},
+	{.addr = 0x214, .wdata = 0x0000},
+	{.addr = 0x216, .wdata = 0x0000},
+	{.addr = 0x218, .wdata = 0x0000},
+	{.addr = 0x225, .wdata = 0x0000},
+	{.addr = 0x22A, .wdata = 0x0000},
+	{.addr = 0x22B, .wdata = 0x0000},
+	{.addr = 0x231, .wdata = 0x0000},
+	{.addr = 0x232, .wdata = 0x0000},
+	{.addr = 0x233, .wdata = 0x0000},
+	{.addr = 0x245, .wdata = 0x0300},
+	{.addr = 0x24A, .wdata = 0x0000},
+	{.addr = 0x24F, .wdata = 0xFFF3},
+	{.addr = 0x254, .wdata = 0x0000},
+	{.addr = 0x259, .wdata = 0x0000},
+	{.addr = 0x25E, .wdata = 0x0000},
+	{.addr = 0x265, .wdata = 0x0009},
+	{.addr = 0x267, .wdata = 0x0174},
+	{.addr = 0x271, .wdata = 0x01F0},
+	{.addr = 0x273, .wdata = 0x0170},
+	{.addr = 0x275, .wdata = 0x7828},
+	{.addr = 0x279, .wdata = 0x3E3A},
+	{.addr = 0x27D, .wdata = 0x8468},
+	{.addr = 0x283, .wdata = 0x000C},
+	{.addr = 0x285, .wdata = 0x7777},
+	{.addr = 0x288, .wdata = 0x5503},
+	{.addr = 0x28C, .wdata = 0x0030},
+	{.addr = 0x28E, .wdata = 0xBBBB},
+	{.addr = 0x290, .wdata = 0xBBBB},
+	{.addr = 0x293, .wdata = 0x0021},
+	{.addr = 0x2FA, .wdata = 0x3B40},
+	{.addr = 0x2FB, .wdata = 0x7777},
+	{.addr = 0x30A, .wdata = 0x8022},
+	{.addr = 0x319, .wdata = 0x205E},
+	{.addr = 0x31B, .wdata = 0x0000},
+	{.addr = 0x31D, .wdata = 0x6004},
+	{.addr = 0x320, .wdata = 0x3014},
+	{.addr = 0x322, .wdata = 0x6004},
+	{.addr = 0x326, .wdata = 0x6004},
+	{.addr = 0x32A, .wdata = 0x5000},
+	{.addr = 0x32E, .wdata = 0x5000},
+	{.addr = 0x332, .wdata = 0x6004},
+	{.addr = 0x336, .wdata = 0x6063},
+	{.addr = 0x389, .wdata = 0x0310},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000},
+	{.addr = 0x3FF, .wdata = 0x0000}
+};
+
+/* returns plu clock p1clk in Hz */
+static u64 mlxbf_gige_calculate_p1clk(struct mlxbf_gige *priv)
+{
+	u8 core_od, core_r;
+	u64 freq_output;
+	u32 reg1, reg2;
+	u32 core_f;
+
+	reg1 = readl(priv->clk_io + MLXBF_GIGE_P1CLK_REG1);
+	reg2 = readl(priv->clk_io + MLXBF_GIGE_P1CLK_REG2);
+
+	core_f = (reg1 & MLXBF_GIGE_P1_CORE_F_MASK) >>
+		MLXBF_GIGE_P1_CORE_F_SHIFT;
+	core_r = (reg1 & MLXBF_GIGE_P1_CORE_R_MASK) >>
+		MLXBF_GIGE_P1_CORE_R_SHIFT;
+	core_od = (reg2 & MLXBF_GIGE_P1_CORE_OD_MASK) >>
+		MLXBF_GIGE_P1_CORE_OD_SHIFT;
+
+	/* Compute PLL output frequency as follow:
+	 *
+	 *                                     CORE_F / 16384
+	 * freq_output = freq_reference * ----------------------------
+	 *                              (CORE_R + 1) * (CORE_OD + 1)
+	 */
+	freq_output = div_u64(MLXBF_GIGE_P1_FREQ_REFERENCE * core_f,
+			      MLXBF_GIGE_P1_CLK_CONST);
+	freq_output = div_u64(freq_output, (core_r + 1) * (core_od + 1));
+
+	return freq_output;
+}
+
+static void mlxbf_gige_ugl_static_config(struct mlxbf_gige *priv)
+{
+	u32 val, p1clk_mhz;
+	u32 const_factor;
+	u64 p1clk;
+
+	/* p1clk is the PLU clock in Hz */
+	p1clk = mlxbf_gige_calculate_p1clk(priv);
+
+	/* get p1clk in MHz */
+	p1clk_mhz = div_u64(p1clk, 1000000);
+
+	/* Multiply the p1clk clock by 12 according to HW requirements */
+	const_factor = p1clk_mhz * MLXBF_GIGE_P1CLK_MULT_FACTOR;
+
+	/* ugl_cr_bridge_desc */
+	val = readl(priv->plu_base + MLXBF_GIGE_UGL_CR_BRIDGE_DESC);
+	val &= ~MLXBF_GIGE_UGL_CR_BRIDGE_ALL_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK,
+			  MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_VAL(const_factor));
+	val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK,
+			  MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_VAL(const_factor));
+	val |= FIELD_PREP(MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK,
+			  MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_UGL_CR_BRIDGE_DESC);
+
+	/* pll1x_fsm_counters */
+	val = MLXBF_GIGE_PLL1X_FSM_DEFAULT_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_DEFAULT_CYCLES);
+
+	val = MLXBF_GIGE_PLL1X_FSM_SLEEP_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_SLEEP_CYCLES);
+
+	val = MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_CYCLES);
+
+	val = MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_CYCLES);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES);
+	val &= ~MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK,
+			  MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES);
+
+	/* tx_fsm_counters */
+	val = MLXBF_GIGE_TX_FSM_DEFAULT_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_DEFAULT_CYCLES);
+
+	val = MLXBF_GIGE_TX_FSM_SLEEP_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_SLEEP_CYCLES);
+
+	val = MLXBF_GIGE_TX_FSM_POWERUP_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_POWERUP_CYCLES);
+
+	val = MLXBF_GIGE_TX_FSM_CAL_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_FLOW_CYCLES);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES);
+	val &= ~MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK,
+			  MLXBF_GIGE_TX_FSM_CAL_ABORT_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES);
+
+	/* rx_fsm_counters */
+	val = MLXBF_GIGE_RX_FSM_DEFAULT_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_DEFAULT_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_SLEEP_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_SLEEP_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_POWERUP_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_POWERUP_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_TERM_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_TERM_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_CAL_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CAL_FLOW_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_CAL_ABORT_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CAL_ABORT_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_EQ_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EQ_FLOW_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_EQ_ABORT_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EQ_ABORT_CYCLES);
+
+	val = MLXBF_GIGE_RX_FSM_EOM_FLOW_VAL(const_factor);
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_EOM_FLOW_CYCLES);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES);
+	val &= ~MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK,
+			  MLXBF_GIGE_RX_FSM_CDR_LOCK_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES);
+
+	/* periodic_flows_timer_max_value */
+	val = readl(priv->plu_base + MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX);
+	val &= ~MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK,
+			  MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX);
+
+	/* plltop.center.iddq_cycles */
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL_IDDQ_CYCLES);
+	val &= ~MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK,
+			  MLXBF_GIGE_PLL_IDDQ_CYCLES_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL_IDDQ_CYCLES);
+
+	/* lanetop.center.iddq_cycles */
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_IDDQ_CYCLES);
+	val &= ~MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK;
+	val |= FIELD_PREP(MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK,
+			  MLXBF_GIGE_LANE_IDDQ_CYCLES_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_IDDQ_CYCLES);
+
+	/* lanetop.center.power_governor0 */
+	val = FIELD_PREP(MLXBF_GIGE_LANE_PWR_GOV0_RISE_MASK,
+			 MLXBF_GIGE_LANE_PWR_GOV0_RISE_VAL(const_factor));
+	val |= FIELD_PREP(MLXBF_GIGE_LANE_PWR_GOV0_FALL_MASK,
+			  MLXBF_GIGE_LANE_PWR_GOV0_FALL_VAL(const_factor));
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_PWR_GOV0);
+}
+
+static int mlxbf_gige_uphy_gw_write(struct mlxbf_gige *priv, u16 addr,
+				    u16 data, bool is_pll)
+{
+	u32 cmd, val;
+	int ret;
+
+	cmd = MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, data, 0, is_pll);
+
+	/* Send PLL or lane GW write request */
+	writel(cmd, priv->plu_base + MLXBF_GIGE_UPHY_GW(is_pll));
+
+	/* If the poll times out, drop the request */
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+					MLXBF_GIGE_UPHY_GW(is_pll),
+					val,
+					!(val & MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll)),
+					5, 1000000);
+	if (ret)
+		dev_dbg(priv->dev, "Failed to send GW write request\n");
+
+	return ret;
+}
+
+static int mlxbf_gige_uphy_gw_read(struct mlxbf_gige *priv, u16 addr,
+				   bool is_pll)
+{
+	u32 cmd, val;
+	int ret;
+
+	cmd = MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, 0, 1, is_pll);
+
+	/* Send PLL or lane GW read request */
+	writel(cmd, priv->plu_base + MLXBF_GIGE_UPHY_GW(is_pll));
+
+	/* If the poll times out, drop the request */
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+					MLXBF_GIGE_UPHY_GW(is_pll),
+					val,
+					!(val & MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll)),
+					5, 1000000);
+	if (ret) {
+		dev_dbg(priv->dev, "Failed to send GW read request\n");
+		return ret;
+	}
+
+	val = readl(priv->plu_base + MLXBF_GIGE_UPHY_GW_DESC0(is_pll));
+	val &= MLXBF_GIGE_UPHY_GW_DESC0_DATA_MASK(is_pll);
+
+	return val;
+}
+
+static int mlxbf_gige_load_uphy_clm_init_pkg(struct mlxbf_gige *priv)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mlxbf_gige_clm_init); i++) {
+		ret = mlxbf_gige_uphy_gw_write(priv,
+					       mlxbf_gige_clm_init[i].addr,
+					       mlxbf_gige_clm_init[i].wdata,
+					       true);
+		if (ret) {
+			dev_dbg(priv->dev, "Failed to load clm init pkg\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_load_clm_production_fuses(struct mlxbf_gige *priv)
+{
+	u8 bg_trim_room;
+	u8 cvb_trim_room;
+	u8 speedo_room;
+	int ret;
+	u32 val;
+
+	val = readl(priv->fuse_gw_io);
+	bg_trim_room = (val & MLXBF_GIGE_YU_BG_TRIM_ROOM_MASK) >>
+			MLXBF_GIGE_YU_BG_TRIM_ROOM_SHIFT;
+	cvb_trim_room = (val & MLXBF_GIGE_YU_CVB_TRIM_ROOM_MASK) >>
+			MLXBF_GIGE_YU_CVB_TRIM_ROOM_SHIFT;
+	speedo_room = (val & MLXBF_GIGE_YU_SPEEDO_ROOM_MASK) >>
+			MLXBF_GIGE_YU_SPEEDO_ROOM_SHIFT;
+
+	val = ((bg_trim_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_VLD_SHIFT);
+	val |= ((cvb_trim_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_VLD_SHIFT);
+	val |= ((speedo_room >> MLXBF_GIGE_YU_FUSE_VALID_SHIFT) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_VLD_SHIFT);
+	val |= ((bg_trim_room & MLXBF_GIGE_YU_FUSE_MASK) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_SHIFT);
+	val |= ((cvb_trim_room & MLXBF_GIGE_YU_FUSE_MASK) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_SHIFT);
+	val |= ((speedo_room & MLXBF_GIGE_YU_FUSE_MASK) <<
+		MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_SHIFT);
+
+	ret = mlxbf_gige_uphy_gw_write(priv, MLXBF_GIGE_MGMT_BGAP_FUSE_CTRL_ADDR, val, true);
+	if (ret)
+		dev_dbg(priv->dev, "Failed to load clm production fuses\n");
+
+	return ret;
+}
+
+static int mlxbf_gige_init_pll(struct mlxbf_gige *priv)
+{
+	int ret;
+
+	ret = mlxbf_gige_load_uphy_clm_init_pkg(priv);
+	if (ret)
+		return ret;
+
+	ret = mlxbf_gige_load_clm_production_fuses(priv);
+
+	return ret;
+}
+
+static int mlxbf_gige_lock_pll(struct mlxbf_gige *priv)
+{
+	int ret;
+	u32 val;
+
+	/* plltop.center.uphy_pll_rst_reg_ */
+	val = readl(priv->plu_base + MLXBF_GIGE_UPHY_PLL_RST_REG);
+	val |= MLXBF_GIGE_UPHY_PLL_RST_REG_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_UPHY_PLL_RST_REG);
+
+	/* cause_or.clrcause.bulk */
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK);
+	val |= MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK);
+
+	writel(0, priv->plu_base + MLXBF_GIGE_PLL_CAL);
+
+	/* Stop polling when fsm state is UGL_PLL1X_FSM_STATE_SLEEP */
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+					MLXBF_GIGE_PLL_FSM_CTRL,
+					val, (val == MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SLEEP),
+					5, 1000000);
+	if (ret) {
+		dev_dbg(priv->dev, "Polling timeout on fsm state sleep\n");
+		return ret;
+	}
+
+	udelay(MLXBF_GIGE_PLL_STAB_TIME);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW);
+	val |= MLXBF_GIGE_PLL_SLEEP_FW_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW);
+
+	udelay(MLXBF_GIGE_PLL_STAB_TIME);
+	writel(MLXBF_GIGE_PLL_RCAL_MASK, priv->plu_base + MLXBF_GIGE_PLL_RCAL);
+
+	/* Stop polling when fsm state is UGL_PLL1X_FSM_STATE_IDLE */
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+					MLXBF_GIGE_PLL_FSM_CTRL,
+					val, (val == MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDLE),
+					5, 1000000);
+	if (ret) {
+		dev_dbg(priv->dev, "Polling timeout on fsm state idle\n");
+		return ret;
+	}
+
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW);
+	val &= ~MLXBF_GIGE_PLL_SLEEP_FW_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL_SLEEP_FW);
+
+	writel(MLXBF_GIGE_PLL_CAL_MASK, priv->plu_base + MLXBF_GIGE_PLL_CAL);
+
+	/* Stop polling when cal_valid is different from 0 */
+	ret = readl_poll_timeout_atomic(priv->plu_base + MLXBF_GIGE_PLL_CAL_VLD,
+					val, !!(val & MLXBF_GIGE_PLL_CAL_VLD_MASK),
+					5, 1000000);
+	if (ret) {
+		dev_dbg(priv->dev, "Polling timeout on cal_valid\n");
+		return ret;
+	}
+
+	/* pll_enable */
+	val = readl(priv->plu_base + MLXBF_GIGE_PLL_ENABLE);
+	val |= MLXBF_GIGE_PLL_ENABLE_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_PLL_ENABLE);
+
+	return ret;
+}
+
+static void mlxbf_gige_get_lane_out_of_rst(struct mlxbf_gige *priv)
+{
+	u32 val;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RST_REG);
+	val |= MLXBF_GIGE_LANE_RST_REG_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RST_REG);
+}
+
+static int mlxbf_gige_load_imem(struct mlxbf_gige *priv)
+{
+	u16 csum_status;
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mlxbf_gige_dlm_imem_init); i++) {
+		ret = mlxbf_gige_uphy_gw_write(priv,
+					       mlxbf_gige_dlm_imem_init[i].addr,
+					       mlxbf_gige_dlm_imem_init[i].wdata,
+					       false);
+		if (ret)
+			return ret;
+	}
+
+	/* Resets the internal counter for MLXBF_GIGE_DLM_IMEM_DATA_ADDR to base address */
+	ret = mlxbf_gige_uphy_gw_write(priv,
+				       mlxbf_gige_dlm_seq_imem_wr_en_init.addr,
+				       mlxbf_gige_dlm_seq_imem_wr_en_init.wdata,
+				       false);
+	if (ret)
+		return ret;
+
+	/* HW increments the address MLXBF_GIGE_DLM_IMEM_DATA_ADDR internally. */
+	for (i = 0; i < ARRAY_SIZE(mlxbf_gige_dlm_imem_data); i++) {
+		ret = mlxbf_gige_uphy_gw_write(priv,
+					       MLXBF_GIGE_LANE_IMEM_DATA_ADDR,
+					       mlxbf_gige_dlm_imem_data[i].wdata,
+					       false);
+		if (ret)
+			return ret;
+	}
+
+	ret = mlxbf_gige_uphy_gw_write(priv,
+				       mlxbf_gige_dlm_seq_imem_wr_dis_init.addr,
+				       mlxbf_gige_dlm_seq_imem_wr_dis_init.wdata,
+				       false);
+	if (ret)
+		return ret;
+
+	ret = mlxbf_gige_uphy_gw_write(priv,
+				       mlxbf_gige_dlm_seq_imem_csum_en.addr,
+				       mlxbf_gige_dlm_seq_imem_csum_en.wdata,
+				       false);
+	if (ret)
+		return ret;
+
+	udelay(MLXBF_GIGE_PLL_DLM_IMEM_CSUM_TIMEOUT);
+
+	ret = mlxbf_gige_uphy_gw_read(priv, MLXBF_GIGE_LANE_CSUM_STS_ADDR, false);
+	if (ret < 0)
+		return ret;
+
+	csum_status = ((ret & MLXBF_GIGE_IMEM_CSUM_STATUS_MASK) >>
+			MLXBF_GIGE_IMEM_CSUM_STATUS_SHIFT);
+
+	ret = mlxbf_gige_uphy_gw_write(priv,
+				       mlxbf_gige_dlm_seq_imem_csum_dis.addr,
+				       mlxbf_gige_dlm_seq_imem_csum_dis.wdata,
+				       false);
+	if (ret)
+		return ret;
+
+	if (csum_status != MLXBF_GIGE_IMEM_CSUM_RUN_AND_VALID) {
+		dev_err(priv->dev, "%s: invalid checksum\n", __func__);
+
+		/* recovery flow */
+		for (i = 0; i < ARRAY_SIZE(mlxbf_gige_dlm_seq_imem_bmap_clr); i++) {
+			mlxbf_gige_uphy_gw_write(priv,
+						 mlxbf_gige_dlm_seq_imem_bmap_clr[i].addr,
+						 mlxbf_gige_dlm_seq_imem_bmap_clr[i].wdata,
+						 false);
+		}
+
+		return MLXBF_GIGE_INVALID_IMEM_CSUM;
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_plu_tx_power_ctrl(struct mlxbf_gige *priv, bool is_pwr_on)
+{
+	int ret = 0;
+	u32 val;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED);
+	val &= ~MLXBF_GIGE_LANE_TX_SLEEP_VAL_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED);
+
+	if (is_pwr_on) {
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+		val &= ~MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+
+		val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+		val |= MLXBF_GIGE_PLU_TX_POWERUP_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+	} else {
+		val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+		val &= ~MLXBF_GIGE_PLU_TX_POWERUP_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+		val |= MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+
+		ret = readl_poll_timeout_atomic(priv->plu_base +
+			MLXBF_GIGE_LANE_TX_FSM_CTRL, val,
+			((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) == MLXBF_GIGE_TX_FSM_IDDQ),
+			5, 1000000);
+		if (ret)
+			dev_dbg(priv->dev, "Polling timeout on tx fsm iddq state\n");
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_dlm_tx_init_pkg(struct mlxbf_gige *priv)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mlxbf_gige_dlm_tx_init); i++) {
+		ret = mlxbf_gige_uphy_gw_write(priv,
+					       mlxbf_gige_dlm_tx_init[i].addr,
+					       mlxbf_gige_dlm_tx_init[i].wdata,
+					       false);
+		if (ret) {
+			dev_dbg(priv->dev, "Failed to load dlm tx init pkg\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_tx_lane_open(struct mlxbf_gige *priv)
+{
+	u32 val;
+	int ret;
+
+	/* Prepare the TX lane before opening it */
+
+	ret = mlxbf_gige_plu_tx_power_ctrl(priv, false);
+	if (ret)
+		return ret;
+
+	/* Calibration of TX elastic buffer */
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+	val &= ~MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK;
+	val |= MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_VAL;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+	val |= MLXBF_GIGE_LANE_TX_DATA_EN_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+
+	writel(MLXBF_GIGE_LANE_TX_CAL_MASK, priv->plu_base + MLXBF_GIGE_LANE_TX_CAL);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+	val &= ~MLXBF_GIGE_LANE_TX_RATE_ID_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED);
+	val &= ~MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED);
+
+	/* Loading the DLM tx init package should be done before lane power on */
+	ret = mlxbf_gige_dlm_tx_init_pkg(priv);
+	if (ret)
+		return ret;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+	val &= ~MLXBF_GIGE_LANE_TX_BITS_SWAP_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+
+	ret = mlxbf_gige_plu_tx_power_ctrl(priv, true);
+	if (ret)
+		return ret;
+
+	/* After preparing the TX lane, open it for data transmission */
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+	val &= ~MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_BITS_SWAP);
+
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+			MLXBF_GIGE_LANE_TX_FSM_CTRL, val,
+			((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) == MLXBF_GIGE_TX_DATA_EN),
+			5, 1000000);
+	if (ret) {
+		dev_dbg(priv->dev, "Polling timeout on fsm tx data enable state\n");
+		return ret;
+	}
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+	val |= MLXBF_GIGE_LANE_TX_PERIODIC_CAL_EN_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_TX_DATA_EN);
+
+	return ret;
+}
+
+static int mlxbf_gige_dlm_rx_init_pkg(struct mlxbf_gige *priv)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mlxbf_gige_dlm_rx_init); i++) {
+		ret = mlxbf_gige_uphy_gw_write(priv,
+					       mlxbf_gige_dlm_rx_init[i].addr,
+					       mlxbf_gige_dlm_rx_init[i].wdata,
+					       false);
+		if (ret) {
+			dev_dbg(priv->dev, "Failed to load dlm rx init pkg\n");
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_plu_rx_power_ctrl(struct mlxbf_gige *priv, bool is_pwr_on)
+{
+	int ret = 0;
+	u32 val;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+	val &= ~MLXBF_GIGE_LANE_RX_SLEEP_VAL_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+
+	if (is_pwr_on) {
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+		val &= ~MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+
+		val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+		val |= MLXBF_GIGE_PLU_RX_POWERUP_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+	} else {
+		/* Enable HW watchdogs. */
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN);
+		val |= MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK;
+		val |= MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN);
+
+		val = readl(priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+		val &= ~MLXBF_GIGE_PLU_RX_POWERUP_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_PLU_POWERUP);
+
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+		val |= MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+
+		ret = readl_poll_timeout_atomic(priv->plu_base +
+			MLXBF_GIGE_LANE_RX_FSM_CTRL, val,
+			((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) == MLXBF_GIGE_RX_FSM_IDDQ),
+			5, 1000000);
+		if (ret) {
+			dev_dbg(priv->dev, "Polling timeout on rx fsm iddq state\n");
+			return ret;
+		}
+
+		val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN);
+		val &= ~MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK;
+		val &= ~MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK;
+		writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN);
+	}
+
+	return ret;
+}
+
+static int mlxbf_gige_rx_lane_open(struct mlxbf_gige *priv)
+{
+	u32 val;
+	int ret;
+
+	ret = mlxbf_gige_plu_rx_power_ctrl(priv, false);
+	if (ret)
+		return ret;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+	val &= ~MLXBF_GIGE_LANE_RX_RATE_ID_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP);
+	val &= ~MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP_RDY_CHICKEN_MASK;
+	val &= ~MLXBF_GIGE_LANE_RX_DATA_SPLIT_LSB_VLD_CHICKEN_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+	val &= ~MLXBF_GIGE_LANE_RX_RATE_ID0_SPEED_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_RATE_ID);
+
+	ret = mlxbf_gige_dlm_rx_init_pkg(priv);
+	if (ret)
+		return ret;
+
+	writel(MLXBF_GIGE_LANE_RX_CAL_MASK, priv->plu_base + MLXBF_GIGE_LANE_RX_CAL);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP);
+	val &= ~MLXBF_GIGE_LANE_RX_CDR_RESET_REG_MASK;
+	val |= MLXBF_GIGE_LANE_RX_CDR_EN_MASK;
+	val |= MLXBF_GIGE_LANE_RX_DATA_EN_MASK;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP);
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_TRAIN);
+	val &= ~MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK;
+	val |= MLXBF_GIGE_LANE_RX_EQ_TRAIN_VAL;
+	writel(val, priv->plu_base + MLXBF_GIGE_LANE_RX_EQ_TRAIN);
+
+	ret = mlxbf_gige_plu_rx_power_ctrl(priv, true);
+	if (ret)
+		return ret;
+
+	ret = readl_poll_timeout_atomic(priv->plu_base +
+			MLXBF_GIGE_LANE_RX_FSM_CTRL, val,
+			((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) == MLXBF_GIGE_RX_FSM_ACTIVE),
+			5, 1000000);
+	if (ret)
+		dev_dbg(priv->dev, "Polling timeout on rx fsm active state\n");
+
+	return ret;
+}
+
+static bool mlxbf_gige_is_uphy_ready(struct mlxbf_gige *priv)
+{
+	u32 val;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_TX_FSM_CTRL);
+	if ((val & MLXBF_GIGE_LANE_TX_FSM_PS_MASK) != MLXBF_GIGE_TX_DATA_EN)
+		return false;
+
+	val = readl(priv->plu_base + MLXBF_GIGE_LANE_RX_FSM_CTRL);
+	if ((val & MLXBF_GIGE_LANE_RX_FSM_PS_MASK) != MLXBF_GIGE_RX_FSM_ACTIVE)
+		return false;
+
+	return true;
+}
+
+int mlxbf_gige_config_uphy(struct mlxbf_gige *priv)
+{
+	struct platform_device *pdev = priv->pdev;
+	struct device *dev = &pdev->dev;
+	int ret = 0;
+
+	priv->fuse_gw_io = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_FUSE_GW);
+	if (IS_ERR(priv->fuse_gw_io))
+		return PTR_ERR(priv->fuse_gw_io);
+
+	if (mlxbf_gige_is_uphy_ready(priv))
+		return 0;
+
+	mlxbf_gige_ugl_static_config(priv);
+	ret = mlxbf_gige_init_pll(priv);
+	if (ret) {
+		dev_err(dev, "%s: Failed to initialize PLL\n", __func__);
+		return ret;
+	}
+
+	ret = mlxbf_gige_lock_pll(priv);
+	if (ret) {
+		dev_err(dev, "%s: Failed to lock PLL\n", __func__);
+		return ret;
+	}
+
+	/* Due to hardware design issue, we need to get the lanes out of reset
+	 * before configuring the imem.
+	 */
+	mlxbf_gige_get_lane_out_of_rst(priv);
+	ret = mlxbf_gige_load_imem(priv);
+	if (ret) {
+		dev_err(dev, "%s: Failed to load imem\n", __func__);
+		return ret;
+	}
+
+	ret = mlxbf_gige_tx_lane_open(priv);
+	if (ret) {
+		dev_err(dev, "%s: Failed to open tx lane\n", __func__);
+		return ret;
+	}
+
+	ret = mlxbf_gige_rx_lane_open(priv);
+	if (ret)
+		dev_err(dev, "%s: Failed to open rx lane\n", __func__);
+
+	return ret;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h
new file mode 100644
index 000000000000..914e627c302a
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_uphy.h
@@ -0,0 +1,398 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */
+
+/* UPHY support for Mellanox Gigabit Ethernet driver
+ *
+ * Copyright (C) 2022 NVIDIA CORPORATION & AFFILIATES
+ */
+
+#ifndef __MLXBF_GIGE_UPHY_H__
+#define __MLXBF_GIGE_UPHY_H__
+
+#include <linux/bitfield.h>
+
+/* Some registers' values depend on the p1clk clock. The following
+ * formula applies:
+ * ((time_in_ns*const_factor)/MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+ */
+#define MLXBF_GIGE_TIME_FACTOR_TO_USEC          10000
+
+/* All addresses represent the offset from the base PLU address */
+
+#define MLXBF_GIGE_PLU_POWERUP                        0x488
+#define MLXBF_GIGE_PLU_TX_POWERUP_MASK                GENMASK(28, 28)
+#define MLXBF_GIGE_PLU_RX_POWERUP_MASK                GENMASK(27, 27)
+
+#define MLXBF_GIGE_LANE_CFG_FLAT0_BASE                0x23000
+#define MLXBF_GIGE_AE_SYS_IMEM_RAM_DATA_CTRL_WDATA    0x23ef8
+#define MLXBF_GIGE_AE_SYS_IMEM_RAM_STAT_IMEM_CSUM_STS 0x23f00
+#define MLXBF_GIGE_IMEM_CSUM_STATUS_MASK              GENMASK(6, 5)
+#define MLXBF_GIGE_IMEM_CSUM_STATUS_SHIFT             5
+
+#define MLXBF_GIGE_PLL_CFG_FLAT0_BASE                         0x25000
+#define MLXBF_GIGE_PLL_CFG_FLAT0_MGMT_BGAP_FUSE_CTRL          0x251d8
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_SHIFT      0
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_SHIFT     4
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_SHIFT       8
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_BG_TRIM_VLD_SHIFT  12
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_CVB_TRIM_VLD_SHIFT 13
+#define MLXBF_GIGE_PLL_MGMT_BGAP_FUSE_CTRL_SPEEDO_VLD_SHIFT   14
+
+#define MLXBF_GIGE_LANE_TX_FSM_CTRL                0x26000
+#define MLXBF_GIGE_LANE_TX_FSM_PS_MASK             GENMASK(3, 0)
+
+#define MLXBF_GIGE_LANE_TX_BITS_SWAP               0x2600c
+#define MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK GENMASK(20, 16)
+#define MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_VAL  \
+	FIELD_PREP(MLXBF_GIGE_TX_EB_BLOCK_PUSH_DIST_MASK_MASK, 0x3)
+#define MLXBF_GIGE_LANE_TX_BITS_SWAP_MASK          GENMASK(0, 0)
+
+#define MLXBF_GIGE_LANE_TX_DATA_EN                 0x26010
+#define MLXBF_GIGE_LANE_TX_RATE_ID_MASK            GENMASK(30, 28)
+#define MLXBF_GIGE_LANE_TX_DATA_EN_MASK            GENMASK(23, 23)
+#define MLXBF_GIGE_LANE_TX_IDDQ_VAL_MASK           GENMASK(21, 21)
+#define MLXBF_GIGE_LANE_TX_PERIODIC_CAL_EN_MASK    GENMASK(17, 17)
+
+#define MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED          0x26014
+#define MLXBF_GIGE_LANE_TX_SLEEP_VAL_MASK          GENMASK(9, 8)
+#define MLXBF_GIGE_LANE_TX_RATE_ID0_SPEED_MASK     GENMASK(2, 0)
+
+#define MLXBF_GIGE_LANE_TX_CAL                     0x26018
+#define MLXBF_GIGE_LANE_TX_CAL_MASK                GENMASK(0, 0)
+
+#define MLXBF_GIGE_LANE_RX_FSM_CTRL                0x26040
+#define MLXBF_GIGE_LANE_RX_FSM_PS_MASK             GENMASK(3, 0)
+
+#define MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN        0x26054
+#define MLXBF_GIGE_LANE_RX_EQ_DONE_TIMER_EN_MASK   GENMASK(31, 31)
+#define MLXBF_GIGE_LANE_RX_CAL_DONE_TIMER_EN_MASK  GENMASK(30, 30)
+
+#define MLXBF_GIGE_LANE_RX_RATE_ID                 0x26058
+#define MLXBF_GIGE_LANE_RX_RATE_ID0_SPEED_MASK     GENMASK(18, 16)
+#define MLXBF_GIGE_LANE_RX_RATE_ID_MASK            GENMASK(14, 12)
+#define MLXBF_GIGE_LANE_RX_SLEEP_VAL_MASK          GENMASK(7, 6)
+#define MLXBF_GIGE_LANE_RX_IDDQ_VAL_MASK           GENMASK(4, 4)
+
+#define MLXBF_GIGE_LANE_RX_CAL                     0x2605c
+#define MLXBF_GIGE_LANE_RX_CAL_MASK                GENMASK(0, 0)
+
+#define MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP                   0x26060
+#define MLXBF_GIGE_LANE_RX_DATA_SPLIT_LSB_VLD_CHICKEN_MASK GENMASK(5, 5)
+#define MLXBF_GIGE_LANE_RX_SYNC_FIFO_POP_RDY_CHICKEN_MASK  GENMASK(4, 4)
+#define MLXBF_GIGE_LANE_RX_CDR_RESET_REG_MASK              GENMASK(3, 3)
+#define MLXBF_GIGE_LANE_RX_CDR_EN_MASK                     GENMASK(2, 2)
+#define MLXBF_GIGE_LANE_RX_DATA_EN_MASK                    GENMASK(1, 1)
+
+#define MLXBF_GIGE_LANE_RX_EQ_TRAIN        0x26064
+#define MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK   GENMASK(2, 0)
+#define MLXBF_GIGE_LANE_RX_EQ_TRAIN_VAL \
+	FIELD_PREP(MLXBF_GIGE_LANE_RX_EQ_TRAIN_MASK, 0x3)
+
+#define MLXBF_GIGE_LANE_GW                 0x26100
+#define MLXBF_GIGE_LANE_GW_ADDR_MASK       GENMASK(10, 1)
+#define MLXBF_GIGE_LANE_GW_RW_MASK         GENMASK(11, 11)
+#define MLXBF_GIGE_LANE_GW_DATA_MASK       GENMASK(27, 12)
+#define MLXBF_GIGE_LANE_GW_DATA_EN_MASK    GENMASK(28, 28)
+#define MLXBF_GIGE_LANE_GW_BUSY_MASK       GENMASK(30, 30)
+#define MLXBF_GIGE_LANE_GW_ADDR_SHIFT      1
+#define MLXBF_GIGE_LANE_GW_DESC0           0x2610c
+#define MLXBF_GIGE_LANE_GW_DESC0_DATA_MASK GENMASK(15, 0)
+
+#define MLXBF_GIGE_TX_FSM_DEFAULT_CYCLES     0x26600
+#define MLXBF_GIGE_TX_FSM_DEFAULT_VAL(const_factor) \
+	((200 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_TX_FSM_SLEEP_CYCLES       0x26604
+#define MLXBF_GIGE_TX_FSM_SLEEP_VAL(const_factor) \
+	((1000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_TX_FSM_POWERUP_CYCLES     0x26608
+#define MLXBF_GIGE_TX_FSM_POWERUP_VAL(const_factor) \
+	((10000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_TX_FSM_CAL_FLOW_CYCLES    0x2660c
+#define MLXBF_GIGE_TX_FSM_CAL_FLOW_VAL(const_factor) \
+	((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_TX_FSM_CAL_ABORT_CYCLES   0x26610
+#define MLXBF_GIGE_TX_FSM_CAL_ABORT_VAL(const_factor) \
+	((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_TX_FSM_CAL_ABORT_MASK     GENMASK(18, 0)
+
+#define MLXBF_GIGE_RX_FSM_DEFAULT_CYCLES     0x26614
+#define MLXBF_GIGE_RX_FSM_DEFAULT_VAL(const_factor) \
+	((200 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_SLEEP_CYCLES       0x26618
+#define MLXBF_GIGE_RX_FSM_SLEEP_VAL(const_factor) \
+	((1000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_POWERUP_CYCLES     0x2661c
+#define MLXBF_GIGE_RX_FSM_POWERUP_VAL(const_factor) \
+	((10000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_TERM_CYCLES        0x26620
+#define MLXBF_GIGE_RX_FSM_TERM_VAL(const_factor) \
+	((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_CAL_FLOW_CYCLES    0x26624
+#define MLXBF_GIGE_RX_FSM_CAL_FLOW_VAL(const_factor) \
+	((200000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_CAL_ABORT_CYCLES   0x26628
+#define MLXBF_GIGE_RX_FSM_CAL_ABORT_VAL(const_factor) \
+	((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_EQ_FLOW_CYCLES     0x2662c
+#define MLXBF_GIGE_RX_FSM_EQ_FLOW_VAL(const_factor) \
+	((48000000 / MLXBF_GIGE_TIME_FACTOR_TO_USEC) * (const_factor))
+
+#define MLXBF_GIGE_RX_FSM_EQ_ABORT_CYCLES    0x26630
+#define MLXBF_GIGE_RX_FSM_EQ_ABORT_VAL(const_factor) \
+	((4000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_RX_FSM_EOM_FLOW_CYCLES    0x26634
+#define MLXBF_GIGE_RX_FSM_EOM_FLOW_VAL(const_factor) \
+	((4000000 / MLXBF_GIGE_TIME_FACTOR_TO_USEC) * (const_factor))
+
+#define MLXBF_GIGE_RX_FSM_CDR_LOCK_CYCLES    0x26638
+#define MLXBF_GIGE_RX_FSM_CDR_LOCK_VAL(const_factor) \
+	((30000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_RX_FSM_CDR_LOCK_MASK      GENMASK(20, 0)
+
+#define MLXBF_GIGE_LANE_PWR_GOV0                   0x26650
+#define MLXBF_GIGE_LANE_PWR_GOV0_FALL_VAL(const_factor) \
+	((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_LANE_PWR_GOV0_FALL_MASK         GENMASK(31, 16)
+#define MLXBF_GIGE_LANE_PWR_GOV0_RISE_VAL(const_factor) \
+	((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_LANE_PWR_GOV0_RISE_MASK         GENMASK(15, 0)
+
+#define MLXBF_GIGE_LANE_IDDQ_CYCLES                0x26660
+#define MLXBF_GIGE_LANE_IDDQ_CYCLES_VAL(const_factor) \
+	((2000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_LANE_IDDQ_CYCLES_MASK           GENMASK(28, 16)
+
+#define MLXBF_GIGE_LANE_RST_REG                    0x26660
+#define MLXBF_GIGE_LANE_RST_REG_MASK               GENMASK(7, 6)
+
+#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX          0x26668
+#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_VAL(const_factor) \
+	((2500000 / (MLXBF_GIGE_TIME_FACTOR_TO_USEC * 8)) * (const_factor))
+#define MLXBF_GIGE_PERIOD_FLOWS_TIMER_MAX_MASK     GENMASK(22, 0)
+
+#define MLXBF_GIGE_PLL_FSM_CTRL           0x26800
+#define MLXBF_GIGE_PLL_FSM_PS_MASK        GENMASK(3, 0)
+
+#define MLXBF_GIGE_PLL_GW                 0x26810
+#define MLXBF_GIGE_PLL_GW_ADDR_MASK       GENMASK(10, 1)
+#define MLXBF_GIGE_PLL_GW_RW_MASK         GENMASK(11, 11)
+#define MLXBF_GIGE_PLL_GW_DATA_MASK       GENMASK(27, 12)
+#define MLXBF_GIGE_PLL_GW_DATA_EN_MASK    GENMASK(28, 28)
+#define MLXBF_GIGE_PLL_GW_BUSY_MASK       GENMASK(30, 30)
+#define MLXBF_GIGE_PLL_GW_ADDR_SHIFT      1
+#define MLXBF_GIGE_PLL_GW_DESC0           0x2681c
+#define MLXBF_GIGE_PLL_GW_DESC0_DATA_MASK GENMASK(15, 0)
+
+#define MLXBF_GIGE_PLL_SLEEP_FW           0x26820
+#define MLXBF_GIGE_PLL_SLEEP_FW_MASK      GENMASK(14, 14)
+
+#define MLXBF_GIGE_PLL_ENABLE             0x26820
+#define MLXBF_GIGE_PLL_ENABLE_MASK        GENMASK(1, 1)
+
+#define MLXBF_GIGE_PLL_RCAL               0x26828
+#define MLXBF_GIGE_PLL_RCAL_MASK          GENMASK(0, 0)
+
+#define MLXBF_GIGE_PLL_CAL_VLD            0x2682c
+#define MLXBF_GIGE_PLL_CAL_VLD_MASK       GENMASK(1, 0)
+
+#define MLXBF_GIGE_PLL_CAL                0x26830
+#define MLXBF_GIGE_PLL_CAL_MASK           GENMASK(0, 0)
+
+#define MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK      0x26878
+#define MLXBF_GIGE_PLL1X_CAUSE_CLRCAUSE_BULK_MASK GENMASK(16, 0)
+
+#define MLXBF_GIGE_PLL1X_FSM_DEFAULT_CYCLES       0x26900
+#define MLXBF_GIGE_PLL1X_FSM_DEFAULT_VAL(const_factor) \
+	((250 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_PLL1X_FSM_SLEEP_CYCLES         0x26904
+#define MLXBF_GIGE_PLL1X_FSM_SLEEP_VAL(const_factor) \
+	((5000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_CYCLES     0x26908
+#define MLXBF_GIGE_PLL1X_FSM_RCAL_FLOW_VAL(const_factor) \
+	((40000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_CYCLES      0x2690c
+#define MLXBF_GIGE_PLL1X_FSM_CAL_FLOW_VAL(const_factor) \
+	((300000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_CYCLES   0x26910
+#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_VAL(const_factor) \
+	((100000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_PLL1X_FSM_LOCKDET_STS_MASK     GENMASK(18, 0)
+
+#define MLXBF_GIGE_PLL_IDDQ_CYCLES           0x26914
+#define MLXBF_GIGE_PLL_IDDQ_CYCLES_VAL(const_factor) \
+	((2000 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_PLL_IDDQ_CYCLES_MASK      GENMASK(28, 16)
+
+#define MLXBF_GIGE_UPHY_PLL_RST_REG          0x26914
+#define MLXBF_GIGE_UPHY_PLL_RST_REG_MASK     GENMASK(2, 2)
+
+#define MLXBF_GIGE_UGL_CR_BRIDGE_DESC       0x26a90
+#define MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK GENMASK(5, 0)
+#define MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK GENMASK(13, 8)
+#define MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK  GENMASK(21, 16)
+#define MLXBF_GIGE_UGL_CR_BRIDGE_ALL_MASK \
+	(MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_MASK | \
+	MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_MASK | \
+	MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_MASK)
+
+#define MLXBF_GIGE_UGL_CR_BRIDGE_SETUP_VAL(const_factor) \
+	((10 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_UGL_CR_BRIDGE_PULSE_VAL(const_factor) \
+	((30 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+#define MLXBF_GIGE_UGL_CR_BRIDGE_HOLD_VAL(const_factor)  \
+	((10 * (const_factor)) / MLXBF_GIGE_TIME_FACTOR_TO_USEC)
+
+/* rw = 0 for write and 1 for read.
+ * data_en should be set to 1 only for a write transaction.
+ */
+#define MLXBF_GIGE_PLL_GW_CREATE_CMD(addr, data, rw) \
+	((((addr) << MLXBF_GIGE_PLL_GW_ADDR_SHIFT) & MLXBF_GIGE_PLL_GW_ADDR_MASK) | \
+	FIELD_PREP(MLXBF_GIGE_PLL_GW_DATA_MASK, data) | \
+	FIELD_PREP(MLXBF_GIGE_PLL_GW_BUSY_MASK, 1) | \
+	(rw ? FIELD_PREP(MLXBF_GIGE_PLL_GW_RW_MASK, 1) : \
+	 FIELD_PREP(MLXBF_GIGE_PLL_GW_DATA_EN_MASK, 1)))
+
+#define MLXBF_GIGE_LANE_GW_CREATE_CMD(addr, data, rw) \
+	((((addr) << MLXBF_GIGE_LANE_GW_ADDR_SHIFT) & MLXBF_GIGE_LANE_GW_ADDR_MASK) | \
+	FIELD_PREP(MLXBF_GIGE_LANE_GW_DATA_MASK, data) | \
+	FIELD_PREP(MLXBF_GIGE_LANE_GW_BUSY_MASK, 1) | \
+	(rw ? FIELD_PREP(MLXBF_GIGE_LANE_GW_RW_MASK, 1) : \
+	 FIELD_PREP(MLXBF_GIGE_LANE_GW_DATA_EN_MASK, 1)))
+
+#define MLXBF_GIGE_UPHY_GW_CREATE_CMD(addr, data, rw, is_pll) \
+	((is_pll) ? MLXBF_GIGE_PLL_GW_CREATE_CMD(addr, data, rw) : \
+	MLXBF_GIGE_LANE_GW_CREATE_CMD(addr, data, rw))
+
+#define MLXBF_GIGE_UPHY_GW(is_pll) \
+	((is_pll) ? MLXBF_GIGE_PLL_GW : MLXBF_GIGE_LANE_GW)
+
+#define MLXBF_GIGE_UPHY_GW_DESC0(is_pll) \
+	((is_pll) ? MLXBF_GIGE_PLL_GW_DESC0 : MLXBF_GIGE_LANE_GW_DESC0)
+
+#define MLXBF_GIGE_UPHY_GW_DESC0_DATA_MASK(is_pll) \
+	((is_pll) ? MLXBF_GIGE_PLL_GW_DESC0_DATA_MASK : \
+	MLXBF_GIGE_LANE_GW_DESC0_DATA_MASK)
+
+#define MLXBF_GIGE_UPHY_GW_BUSY_MASK(is_pll) \
+	((is_pll) ? MLXBF_GIGE_PLL_GW_BUSY_MASK : \
+	MLXBF_GIGE_LANE_GW_BUSY_MASK)
+
+/* bootrecord p1clk */
+#define MLXBF_GIGE_P1CLK_REG1        0x14
+#define MLXBF_GIGE_P1CLK_REG2        0x18
+#define MLXBF_GIGE_P1_CORE_F_SHIFT   0
+#define MLXBF_GIGE_P1_CORE_F_MASK    GENMASK(25, 0)
+#define MLXBF_GIGE_P1_CORE_R_SHIFT   26
+#define MLXBF_GIGE_P1_CORE_R_MASK    GENMASK(31, 26)
+#define MLXBF_GIGE_P1_CORE_OD_SHIFT  0
+#define MLXBF_GIGE_P1_CORE_OD_MASK   GENMASK(3, 0)
+
+#define MLXBF_GIGE_P1CLK_MULT_FACTOR 12
+#define MLXBF_GIGE_P1_FREQ_REFERENCE 156250000ULL
+#define MLXBF_GIGE_P1_CLK_CONST      16384ULL
+
+/* There is a 32-bit crspace to 16-bit UPHY address encoding.
+ * The 16-bit address can be accessed via the GW register.
+ * Subtract the crspace region base address from the actual
+ * address that needs to be accessed via the gw.
+ * Then divide it by 4 since crspace registers are 4 bit aligned
+ */
+#define MLXBF_GIGE_32B_TO_16B_ADDR(addr, base) (((addr) - (base)) >> 2)
+
+#define MLXBF_GIGE_LANE_CSUM_STS_ADDR \
+	MLXBF_GIGE_32B_TO_16B_ADDR( \
+	MLXBF_GIGE_AE_SYS_IMEM_RAM_STAT_IMEM_CSUM_STS, \
+	MLXBF_GIGE_LANE_CFG_FLAT0_BASE)
+
+#define MLXBF_GIGE_IMEM_CSUM_RUN_AND_VALID              0x3
+#define MLXBF_GIGE_INVALID_IMEM_CSUM                    -1
+
+#define MLXBF_GIGE_LANE_IMEM_DATA_ADDR \
+	MLXBF_GIGE_32B_TO_16B_ADDR( \
+	MLXBF_GIGE_AE_SYS_IMEM_RAM_DATA_CTRL_WDATA, \
+	MLXBF_GIGE_LANE_CFG_FLAT0_BASE)
+
+#define MLXBF_GIGE_MGMT_BGAP_FUSE_CTRL_ADDR \
+	MLXBF_GIGE_32B_TO_16B_ADDR( \
+	MLXBF_GIGE_PLL_CFG_FLAT0_MGMT_BGAP_FUSE_CTRL, \
+	MLXBF_GIGE_PLL_CFG_FLAT0_BASE)
+
+#define MLXBF_GIGE_YU_BG_TRIM_ROOM_MASK   GENMASK(4, 0)
+#define MLXBF_GIGE_YU_BG_TRIM_ROOM_SHIFT  0
+#define MLXBF_GIGE_YU_CVB_TRIM_ROOM_MASK  GENMASK(9, 5)
+#define MLXBF_GIGE_YU_CVB_TRIM_ROOM_SHIFT 5
+#define MLXBF_GIGE_YU_SPEEDO_ROOM_MASK    GENMASK(14, 10)
+#define MLXBF_GIGE_YU_SPEEDO_ROOM_SHIFT   10
+#define MLXBF_GIGE_YU_FUSE_VALID_SHIFT    4
+/* Fuse mask without valid bit */
+#define MLXBF_GIGE_YU_FUSE_MASK           0xf
+
+enum {
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDDQ,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SLEEP,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_RCAL_DONE_WAIT1,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_RCAL_DONE_WAIT0,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_IDLE,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_CAL_DONE_WAIT1,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_CAL_DONE_WAIT0,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_ACTIVE,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_LOCK,
+	MLXBF_GIGE_UGL_PLL1X_FSM_STATE_SPEED_CHANGE
+};
+
+enum {
+	MLXBF_GIGE_TX_FSM_IDDQ,
+	MLXBF_GIGE_TX_FSM_SLEEP,
+	MLXBF_GIGE_TX_FSM_SPEED_CHANGE,
+	MLXBF_GIGE_TX_FSM_POWERUP,
+	MLXBF_GIGE_TX_UGL_TX_POWERUP,
+	MLXBF_GIGE_TX_CAL_DONE_WAIT1,
+	MLXBF_GIGE_TX_CAL_ABORT,
+	MLXBF_GIGE_TX_CAL_ABORT_DONE_WAIT1,
+	MLXBF_GIGE_TX_CAL_DONE_WAIT0,
+	MLXBF_GIGE_TX_CAL_DONE,
+	MLXBF_GIGE_TX_DATA_READY,
+	MLXBF_GIGE_TX_DATA_EN_RDY,
+	MLXBF_GIGE_TX_DATA_EN
+};
+
+enum {
+	MLXBF_GIGE_RX_FSM_IDDQ,
+	MLXBF_GIGE_RX_FSM_SLEEP,
+	MLXBF_GIGE_RX_FSM_SPEED_CHANGE,
+	MLXBF_GIGE_RX_FSM_POWERUP,
+	MLXBF_GIGE_RX_FSM_CAL,
+	MLXBF_GIGE_RX_FSM_WAIT_TERM,
+	MLXBF_GIGE_RX_FSM_DATA_EN_RDY,
+	MLXBF_GIGE_RX_FSM_DATA_EN,
+	MLXBF_GIGE_RX_FSM_CDR_EN,
+	MLXBF_GIGE_RX_FSM_ACTIVE,
+	MLXBF_GIGE_RX_FSM_EQ,
+	MLXBF_GIGE_RX_FSM_EOM
+};
+
+#define MLXBF_GIGE_PLL_STAB_TIME             6 /* us */
+#define MLXBF_GIGE_PLL_DLM_IMEM_CSUM_TIMEOUT 15 /* us */
+
+struct mlxbf_gige_uphy_cfg_reg {
+	u16 addr;
+	u16 wdata;
+};
+
+int mlxbf_gige_config_uphy(struct mlxbf_gige *priv);
+
+#endif /* __MLXBF_GIGE_UPHY_H__ */
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback
  2022-11-09 22:47 [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support David Thompson
                   ` (2 preceding siblings ...)
  2022-11-09 22:47 ` [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration David Thompson
@ 2022-11-09 22:47 ` David Thompson
  2022-11-10 13:26   ` Andrew Lunn
  3 siblings, 1 reply; 19+ messages in thread
From: David Thompson @ 2022-11-09 22:47 UTC (permalink / raw)
  To: davem, edumazet, kuba, pabeni
  Cc: netdev, cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	David Thompson, Asmaa Mnebhi

This patch extends the "ethtool_ops" data structure to
include the "set_link_ksettings" callback. This change
enables configuration of the various interface speeds
that the BlueField-3 supports (10Mbps, 100Mbps, and 1Gbps).

Signed-off-by: David Thompson <davthompson@nvidia.com>
Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
---
 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 1 +
 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
index 41ebef25a930..253d7ad9b809 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
@@ -135,4 +135,5 @@ const struct ethtool_ops mlxbf_gige_ethtool_ops = {
 	.nway_reset		= phy_ethtool_nway_reset,
 	.get_pauseparam		= mlxbf_gige_get_pauseparam,
 	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
+	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
 };
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index 80060a54ba95..a9fa662e0665 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -224,7 +224,7 @@ static int mlxbf_gige_stop(struct net_device *netdev)
 }
 
 static int mlxbf_gige_eth_ioctl(struct net_device *netdev,
-			       struct ifreq *ifr, int cmd)
+				struct ifreq *ifr, int cmd)
 {
 	if (!(netif_running(netdev)))
 		return -EINVAL;
-- 
2.30.1


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3
  2022-11-09 22:47 ` [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3 David Thompson
@ 2022-11-10 13:23   ` Andrew Lunn
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Lunn @ 2022-11-10 13:23 UTC (permalink / raw)
  To: David Thompson
  Cc: davem, edumazet, kuba, pabeni, netdev, cai.huoqing, brgl,
	limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Wed, Nov 09, 2022 at 05:47:50PM -0500, David Thompson wrote:
> The BlueField-3 OOB interface supports 10Mbps, 100Mbps, and 1Gbps speeds.
> The external PHY is responsible for autonegotiating the speed with the
> link partner. Once the autonegotiation is done, the BlueField PLU needs
> to be configured accordingly.
> 
> This patch does two things:
> 1) Initialize the advertised control flow/duplex/speed in the probe
>    based on the BlueField SoC generation (2 or 3)
> 2) Adjust the PLU speed config in the PHY interrupt handler
> 
> Signed-off-by: David Thompson <davthompson@nvidia.com>
> Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3
  2022-11-09 22:47 ` [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3 David Thompson
@ 2022-11-10 13:24   ` Andrew Lunn
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Lunn @ 2022-11-10 13:24 UTC (permalink / raw)
  To: David Thompson
  Cc: davem, edumazet, kuba, pabeni, netdev, cai.huoqing, brgl,
	limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Wed, Nov 09, 2022 at 05:47:49PM -0500, David Thompson wrote:
> This patch adds initial MDIO support for the BlueField-3
> SoC. Separate header files for the BlueField-2 and the
> BlueField-3 SoCs have been created.  These header files
> hold the SoC-specific MDIO macros since the register
> offsets and bit fields have changed.  Also, in BlueField-3
> there is a separate register for writing and reading the
> MDIO data.  Finally, instead of having "if" statements
> everywhere to differentiate between SoC-specific logic,
> a mlxbf_gige_mdio_gw_t struct was created for this purpose.
> 
> Signed-off-by: David Thompson <davthompson@nvidia.com>
> Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback
  2022-11-09 22:47 ` [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback David Thompson
@ 2022-11-10 13:26   ` Andrew Lunn
  0 siblings, 0 replies; 19+ messages in thread
From: Andrew Lunn @ 2022-11-10 13:26 UTC (permalink / raw)
  To: David Thompson
  Cc: davem, edumazet, kuba, pabeni, netdev, cai.huoqing, brgl,
	limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Wed, Nov 09, 2022 at 05:47:52PM -0500, David Thompson wrote:
> This patch extends the "ethtool_ops" data structure to
> include the "set_link_ksettings" callback. This change
> enables configuration of the various interface speeds
> that the BlueField-3 supports (10Mbps, 100Mbps, and 1Gbps).
> 
> Signed-off-by: David Thompson <davthompson@nvidia.com>
> Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
> ---
>  drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 1 +
>  drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c    | 2 +-
>  2 files changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
> index 41ebef25a930..253d7ad9b809 100644
> --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
> +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c
> @@ -135,4 +135,5 @@ const struct ethtool_ops mlxbf_gige_ethtool_ops = {
>  	.nway_reset		= phy_ethtool_nway_reset,
>  	.get_pauseparam		= mlxbf_gige_get_pauseparam,
>  	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
> +	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
>  };
> diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> index 80060a54ba95..a9fa662e0665 100644
> --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
> @@ -224,7 +224,7 @@ static int mlxbf_gige_stop(struct net_device *netdev)
>  }
>  
>  static int mlxbf_gige_eth_ioctl(struct net_device *netdev,
> -			       struct ifreq *ifr, int cmd)
> +				struct ifreq *ifr, int cmd)
>  {
>  	if (!(netif_running(netdev)))
>  		return -EINVAL;

White space changes should be in a separate patch.

With this fixed:

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-09 22:47 ` [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration David Thompson
@ 2022-11-10 13:33   ` Andrew Lunn
  2022-11-12  5:34     ` Jakub Kicinski
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-11-10 13:33 UTC (permalink / raw)
  To: David Thompson
  Cc: davem, edumazet, kuba, pabeni, netdev, cai.huoqing, brgl,
	limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Wed, Nov 09, 2022 at 05:47:51PM -0500, David Thompson wrote:
> The BlueField-3 out-of-band Ethernet interface requires
> SerDes configuration. There are two aspects to this:
> 
> Configuration of PLL:
>     1) Initialize UPHY registers to values dependent on p1clk clock
>     2) Load PLL best known values via the gateway register
>     3) Set the fuses to tune up the SerDes voltage
>     4) Lock the PLL
>     5) Get the lanes out of functional reset.
>     6) Configure the UPHY microcontroller via gateway reads/writes
> 
> Configuration of lanes:
>     1) Configure and open TX lanes
>     2) Configure and open RX lanes

I still don't like all these black magic tables in the driver.

But lets see what others say.

    Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-10 13:33   ` Andrew Lunn
@ 2022-11-12  5:34     ` Jakub Kicinski
  2022-11-12  9:52       ` Saeed Mahameed
  0 siblings, 1 reply; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-12  5:34 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: David Thompson, davem, edumazet, pabeni, netdev, cai.huoqing,
	brgl, limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Thu, 10 Nov 2022 14:33:47 +0100 Andrew Lunn wrote:
> On Wed, Nov 09, 2022 at 05:47:51PM -0500, David Thompson wrote:
> > The BlueField-3 out-of-band Ethernet interface requires
> > SerDes configuration. There are two aspects to this:
> > 
> > Configuration of PLL:
> >     1) Initialize UPHY registers to values dependent on p1clk clock
> >     2) Load PLL best known values via the gateway register
> >     3) Set the fuses to tune up the SerDes voltage
> >     4) Lock the PLL
> >     5) Get the lanes out of functional reset.
> >     6) Configure the UPHY microcontroller via gateway reads/writes
> > 
> > Configuration of lanes:
> >     1) Configure and open TX lanes
> >     2) Configure and open RX lanes  
> 
> I still don't like all these black magic tables in the driver.
> 
> But lets see what others say.

Well, the patch was marked as Changes Requested so it seems that DaveM
concurs :) (I'm slightly desensitized to those tables because they
happen in WiFi relatively often.)

The recommendation is to come up with a format for a binary file, load
it via FW loader and then parse in the kernel?

We did have a recommendation against parsing FW files in the kernel at
some point, too, but perhaps this is simple enough to pass.

Should this be shared infra? The problem is fairly common.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-12  5:34     ` Jakub Kicinski
@ 2022-11-12  9:52       ` Saeed Mahameed
  2022-11-12 15:53         ` Andrew Lunn
  2022-11-15  0:50         ` Jakub Kicinski
  0 siblings, 2 replies; 19+ messages in thread
From: Saeed Mahameed @ 2022-11-12  9:52 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Andrew Lunn, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On 11 Nov 21:34, Jakub Kicinski wrote:
>On Thu, 10 Nov 2022 14:33:47 +0100 Andrew Lunn wrote:
>> On Wed, Nov 09, 2022 at 05:47:51PM -0500, David Thompson wrote:
>> > The BlueField-3 out-of-band Ethernet interface requires
>> > SerDes configuration. There are two aspects to this:
>> >
>> > Configuration of PLL:
>> >     1) Initialize UPHY registers to values dependent on p1clk clock
>> >     2) Load PLL best known values via the gateway register
>> >     3) Set the fuses to tune up the SerDes voltage
>> >     4) Lock the PLL
>> >     5) Get the lanes out of functional reset.
>> >     6) Configure the UPHY microcontroller via gateway reads/writes
>> >
>> > Configuration of lanes:
>> >     1) Configure and open TX lanes
>> >     2) Configure and open RX lanes
>>
>> I still don't like all these black magic tables in the driver.
>>
>> But lets see what others say.
>
>Well, the patch was marked as Changes Requested so it seems that DaveM
>concurs :) (I'm slightly desensitized to those tables because they
>happen in WiFi relatively often.)
>
>The recommendation is to come up with a format for a binary file, load
>it via FW loader and then parse in the kernel?

By FW loader you mean request_firmware() functionality ?

I am not advocating for black magic tables of course :), but how do we
avoid them if request_firmware() will be an overkill to configure such a
simple device? Express such data in a developer friendly c structures
with somewhat sensible field names?

>
>We did have a recommendation against parsing FW files in the kernel at
>some point, too, but perhaps this is simple enough to pass.
>
>Should this be shared infra? The problem is fairly common.

Infrastructure to parse vendor Firmware ? we can't get vendors to agree on
ethtool interface, you want them to agree on one firmware format :)?

BTW i don't think the issue here is firmware at all, this is device
specific config space.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-12  9:52       ` Saeed Mahameed
@ 2022-11-12 15:53         ` Andrew Lunn
  2022-11-15  0:56           ` Jakub Kicinski
  2022-11-15  0:50         ` Jakub Kicinski
  1 sibling, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-11-12 15:53 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: Jakub Kicinski, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

> > The recommendation is to come up with a format for a binary file, load
> > it via FW loader and then parse in the kernel?
> 
> By FW loader you mean request_firmware() functionality ?
> 
> I am not advocating for black magic tables of course :), but how do we
> avoid them if request_firmware() will be an overkill to configure such a
> simple device? Express such data in a developer friendly c structures
> with somewhat sensible field names?

Do you think anybody other than your company has the ability to change
these values? Is there useful documentation about what they do, even
if it is under NDA? Why would somebody actually need to change them?

Is here functionally here which you don't support but the community
might like to add?

Expressing the data in a developer friendly C structure only really
make sense if there is a small collection of developers out there who
have the skills, documentation and maybe equipment to actually make
meaningful changes.

I don't like making it harder to some clever people to hack new stuff
into your drivers, but there are so few contributions from the
community to your drivers that it might as well be black magic, and
just load the values from a file.

       Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-12  9:52       ` Saeed Mahameed
  2022-11-12 15:53         ` Andrew Lunn
@ 2022-11-15  0:50         ` Jakub Kicinski
  2022-11-15  1:06           ` Andrew Lunn
  1 sibling, 1 reply; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-15  0:50 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: Andrew Lunn, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On Sat, 12 Nov 2022 01:52:47 -0800 Saeed Mahameed wrote:
> >Well, the patch was marked as Changes Requested so it seems that DaveM
> >concurs :) (I'm slightly desensitized to those tables because they
> >happen in WiFi relatively often.)
> >
> >The recommendation is to come up with a format for a binary file, load
> >it via FW loader and then parse in the kernel?  
> 
> By FW loader you mean request_firmware() functionality ?

Yes, that's what I meant.

> I am not advocating for black magic tables of course :), but how do we
> avoid them if request_firmware() will be an overkill to configure such a
> simple device? Express such data in a developer friendly c structures
> with somewhat sensible field names?

I don't feel particularly strongly but seems like something worth
exploring. A minor advantage is that once the init is done the tables
can be discarded from memory.

> >We did have a recommendation against parsing FW files in the kernel at
> >some point, too, but perhaps this is simple enough to pass.
> >
> >Should this be shared infra? The problem is fairly common.  
> 
> Infrastructure to parse vendor Firmware ? we can't get vendors to agree on
> ethtool interface, you want them to agree on one firmware format :)?

We can keep the table format pretty much as is. What I had in mind was
basically creating a binary file format with u64 address, and u64 data.
Plus file sections to pack multiple tables into one file.
Pretty pleasant coding exercise if you ask me :)

> BTW i don't think the issue here is firmware at all, this is device
> specific config space.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-12 15:53         ` Andrew Lunn
@ 2022-11-15  0:56           ` Jakub Kicinski
  0 siblings, 0 replies; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-15  0:56 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Saeed Mahameed, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On Sat, 12 Nov 2022 16:53:28 +0100 Andrew Lunn wrote:
> Do you think anybody other than your company has the ability to change
> these values? Is there useful documentation about what they do, even
> if it is under NDA? Why would somebody actually need to change them?
> 
> Is here functionally here which you don't support but the community
> might like to add?
> 
> Expressing the data in a developer friendly C structure only really
> make sense if there is a small collection of developers out there who
> have the skills, documentation and maybe equipment to actually make
> meaningful changes.

+1, even if the tables are not "FW as in compiled code" it's still 
"FW as in opaque blob". Plus if the format is well known and documented
modifying the files is not harder than changing the kernel.

I think the applicability would be much wider. I will definitely make
the WiFi people use this mechanism:

  drivers/net/wireless/realtek/rtw89/rtw8852a_table.c

ugh.

> I don't like making it harder to some clever people to hack new stuff
> into your drivers, but there are so few contributions from the
> community to your drivers that it might as well be black magic, and
> just load the values from a file.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-15  0:50         ` Jakub Kicinski
@ 2022-11-15  1:06           ` Andrew Lunn
  2022-11-15  1:13             ` Jakub Kicinski
  0 siblings, 1 reply; 19+ messages in thread
From: Andrew Lunn @ 2022-11-15  1:06 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Saeed Mahameed, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

  > I am not advocating for black magic tables of course :), but how do we
> > avoid them if request_firmware() will be an overkill to configure such a
> > simple device? Express such data in a developer friendly c structures
> > with somewhat sensible field names?
> 
> I don't feel particularly strongly but seems like something worth
> exploring. A minor advantage is that once the init is done the tables
> can be discarded from memory.

I wondered about that, but i'm not sure initdata works for modules,
and for hot pluggable devices like PCIe, you never know when another
one might appear and you need the tables.

    Andrew

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-15  1:06           ` Andrew Lunn
@ 2022-11-15  1:13             ` Jakub Kicinski
  2022-11-16 16:30               ` Jakub Kicinski
  0 siblings, 1 reply; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-15  1:13 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Saeed Mahameed, David Thompson, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On Tue, 15 Nov 2022 02:06:19 +0100 Andrew Lunn wrote:
>   > I am not advocating for black magic tables of course :), but how do we  
> > > avoid them if request_firmware() will be an overkill to configure such a
> > > simple device? Express such data in a developer friendly c structures
> > > with somewhat sensible field names?  
> > 
> > I don't feel particularly strongly but seems like something worth
> > exploring. A minor advantage is that once the init is done the tables
> > can be discarded from memory.  
> 
> I wondered about that, but i'm not sure initdata works for modules,
> and for hot pluggable devices like PCIe, you never know when another
> one might appear and you need the tables.

Right, I meant that the request_firmware() version can discard 
the tables. I shouldn't have said tables :)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-15  1:13             ` Jakub Kicinski
@ 2022-11-16 16:30               ` Jakub Kicinski
  2022-11-17  2:01                 ` Saeed Mahameed
  0 siblings, 1 reply; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-16 16:30 UTC (permalink / raw)
  To: Saeed Mahameed, David Thompson
  Cc: Andrew Lunn, davem, edumazet, pabeni, netdev, cai.huoqing, brgl,
	limings, chenhao288, huangguangbin2, Asmaa Mnebhi

On Mon, 14 Nov 2022 17:13:05 -0800 Jakub Kicinski wrote:
> On Tue, 15 Nov 2022 02:06:19 +0100 Andrew Lunn wrote:
> > > I don't feel particularly strongly but seems like something worth
> > > exploring. A minor advantage is that once the init is done the tables
> > > can be discarded from memory.    
> > 
> > I wondered about that, but i'm not sure initdata works for modules,
> > and for hot pluggable devices like PCIe, you never know when another
> > one might appear and you need the tables.  
> 
> Right, I meant that the request_firmware() version can discard 
> the tables. I shouldn't have said tables :)

Saeed, David, are you looking into this? The problem come up again 
in a Realtek USB conversation.

The task is so small and well defined I'm pretty sure I can get some
aspiring kernel developer at Meta to knock it off in a few days.

FWIW the structure of a file I had in mind would be something like this:

# Section 0 - strings (must be section 0)
 # header
 u32 type:   1   # string section
 u32 length: n   # length excluding header and pads
 u32 name:   0   # offset to the name in str section
 u32 pad:    0   # align to 8B
 # data
 .str\0table_abc\0table_def\0some_other_string\0
 # pad, align to 8B
 \0\0\0\0\0\0\0

# Section 1 - table_abc
 # header
 u32 type:   2   # 32b/32b table
 u32 length: 64  # length excluding header and pads
 u32 name:   5   # offset to the name in str section
 u32 pad:    0
 # data
 [ 0x210, 0xc00ff ]
 [ 0x214, 0xffeee ]
 [ 0x218, 0xdeaddd ]
 [ 0x21c, 0xc4ee5e ]
 [ 0x220, 0xc00ff ]
 [ 0x224, 0xffeee ]
 [ 0x228, 0xdeaddd ]
 [ 0x22c, 0xc4ee5e ]

etc.

Use:
	struct fw_table32 *abc, *def;

	fw = request_firmware("whatever_name.ftb");
	
	abc = fw_table_get(fw, "table_abc");
	/* use abc */

	def = fw_table_get(fw, "table_def");
	/* use def */

	release_firmware(fw)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-16 16:30               ` Jakub Kicinski
@ 2022-11-17  2:01                 ` Saeed Mahameed
  2022-11-17  6:23                   ` Jakub Kicinski
  0 siblings, 1 reply; 19+ messages in thread
From: Saeed Mahameed @ 2022-11-17  2:01 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: David Thompson, Andrew Lunn, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On 16 Nov 08:30, Jakub Kicinski wrote:
>On Mon, 14 Nov 2022 17:13:05 -0800 Jakub Kicinski wrote:
>> On Tue, 15 Nov 2022 02:06:19 +0100 Andrew Lunn wrote:
>> > > I don't feel particularly strongly but seems like something worth
>> > > exploring. A minor advantage is that once the init is done the tables
>> > > can be discarded from memory.
>> >
>> > I wondered about that, but i'm not sure initdata works for modules,
>> > and for hot pluggable devices like PCIe, you never know when another
>> > one might appear and you need the tables.
>>
>> Right, I meant that the request_firmware() version can discard
>> the tables. I shouldn't have said tables :)
>
>Saeed, David, are you looking into this? The problem come up again
>in a Realtek USB conversation.
>
>The task is so small and well defined I'm pretty sure I can get some
>aspiring kernel developer at Meta to knock it off in a few days.
>

Give me a couple of days and will let you know what's the verdict.
I sent David and Asmaa the links to read up on Request Firmware. Still
waiting for a response.

>FWIW the structure of a file I had in mind would be something like this:
>
># Section 0 - strings (must be section 0)
> # header
> u32 type:   1   # string section
> u32 length: n   # length excluding header and pads
> u32 name:   0   # offset to the name in str section
> u32 pad:    0   # align to 8B
> # data
> .str\0table_abc\0table_def\0some_other_string\0
> # pad, align to 8B
> \0\0\0\0\0\0\0
>
># Section 1 - table_abc
> # header
> u32 type:   2   # 32b/32b table
> u32 length: 64  # length excluding header and pads
> u32 name:   5   # offset to the name in str section
> u32 pad:    0
> # data
> [ 0x210, 0xc00ff ]
> [ 0x214, 0xffeee ]
> [ 0x218, 0xdeaddd ]
> [ 0x21c, 0xc4ee5e ]
> [ 0x220, 0xc00ff ]
> [ 0x224, 0xffeee ]
> [ 0x228, 0xdeaddd ]
> [ 0x22c, 0xc4ee5e ]
>
>etc.
>
>Use:
>	struct fw_table32 *abc, *def;
>
>	fw = request_firmware("whatever_name.ftb");
>	
>	abc = fw_table_get(fw, "table_abc");
>	/* use abc */
>

abc is just a byte buffer ? right ?

>	def = fw_table_get(fw, "table_def");
>	/* use def */
>

And what goes here? any constraints on how the driver must interpret
and handle abc/def blobs ? 

>	release_firmware(fw)

What if the same abc blob structure/table format is used to setup dynamic link
properties, say via ethtool -s ? Then the whole request firmware will be
redundant since "struct abc {};" must be defined in the driver src code.

I like the idea, i am just trying to figure how we are going to define it
and how developers will differentiate between when to use this or when to
use standard APIs to setup their devices.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration
  2022-11-17  2:01                 ` Saeed Mahameed
@ 2022-11-17  6:23                   ` Jakub Kicinski
  0 siblings, 0 replies; 19+ messages in thread
From: Jakub Kicinski @ 2022-11-17  6:23 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: David Thompson, Andrew Lunn, davem, edumazet, pabeni, netdev,
	cai.huoqing, brgl, limings, chenhao288, huangguangbin2,
	Asmaa Mnebhi

On Wed, 16 Nov 2022 18:01:41 -0800 Saeed Mahameed wrote:
> >	fw = request_firmware("whatever_name.ftb");
> >	
> >	abc = fw_table_get(fw, "table_abc");
> >	/* use abc */
> >  
> 
> abc is just a byte buffer ? right ?

pointer to const struct fw_table32, which is just;

struct fw_table32 {
	u32 addr;
	u32 value;
};

Actually we need the length as well, so perhaps this is better:

struct fw_table32 {
	u32 addr;
	u32 val;
};

struct fw_table_result {
	uint cnt;
	union {
		const struct fw_table32 *tb32;
	};
};

User:

	struct fw_table_result tab;

	fw = request_firmware("whatever_name.ftb");
	if (!fw)
		...

	err = fw_table_get(fw, "table_abc", &tab);
	if (err)
		...
	for (i = 0; i < tab.cnt; i++) /* use abc */
		write_or_whatever(hw, tab.tb32[i].addr, tab.tb32[i].val);

	def = fw_table_get(fw, "table_def");
	if (err)
		...
	for (i = 0; i < tab.cnt; i++) /* use def */
		write_or_whatever(hw, tab.tb32[i].addr, tab.tb32[i].val);

	release_firmware(fw)

> >	def = fw_table_get(fw, "table_def");
> >	/* use def */
> >  
> 
> And what goes here? any constraints on how the driver must interpret
> and handle abc/def blobs ? 

In the example I assumed a typical buffer with addr / value pairs.
But we can define more table types as needed.

> >	release_firmware(fw)  
> 
> What if the same abc blob structure/table format is used to setup dynamic link
> properties, say via ethtool -s ? Then the whole request firmware will be
> redundant since "struct abc {};" must be defined in the driver src code.

No complex structures, we'd be only targeting register init 
and small FW blobs (IOW { u32 addr; u32 val; } and { u8 val; }).
Stuff which Windows? drivers tend to put into the code as static array.

> I like the idea, i am just trying to figure how we are going to define it
> and how developers will differentiate between when to use this or when to
> use standard APIs to setup their devices.


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2022-11-17  6:23 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-09 22:47 [PATCH net-next v2 0/4] mlxbf_gige: add BlueField-3 support David Thompson
2022-11-09 22:47 ` [PATCH net-next v2 1/4] mlxbf_gige: add MDIO support for BlueField-3 David Thompson
2022-11-10 13:24   ` Andrew Lunn
2022-11-09 22:47 ` [PATCH net-next v2 2/4] mlxbf_gige: support 10M/100M/1G speeds on BlueField-3 David Thompson
2022-11-10 13:23   ` Andrew Lunn
2022-11-09 22:47 ` [PATCH net-next v2 3/4] mlxbf_gige: add BlueField-3 Serdes configuration David Thompson
2022-11-10 13:33   ` Andrew Lunn
2022-11-12  5:34     ` Jakub Kicinski
2022-11-12  9:52       ` Saeed Mahameed
2022-11-12 15:53         ` Andrew Lunn
2022-11-15  0:56           ` Jakub Kicinski
2022-11-15  0:50         ` Jakub Kicinski
2022-11-15  1:06           ` Andrew Lunn
2022-11-15  1:13             ` Jakub Kicinski
2022-11-16 16:30               ` Jakub Kicinski
2022-11-17  2:01                 ` Saeed Mahameed
2022-11-17  6:23                   ` Jakub Kicinski
2022-11-09 22:47 ` [PATCH net-next v2 4/4] mlxbf_gige: add "set_link_ksettings" ethtool callback David Thompson
2022-11-10 13:26   ` Andrew Lunn

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.