DPDK patches and discussions
 help / color / mirror / Atom feed
From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, ckm@napatech.com,
	andrew.rybchenko@oktetlabs.ru, ferruh.yigit@amd.com
Subject: [PATCH v2 12/17] net/ntnic: add support of the NT200A0X smartNIC
Date: Fri, 31 May 2024 17:47:16 +0200	[thread overview]
Message-ID: <20240531154731.1856874-12-sil-plv@napatech.com> (raw)
In-Reply-To: <20240531154731.1856874-1-sil-plv@napatech.com>

Add ntnic support for NT200A0X NIC

* Reset

* Clock profiles

* FPGA Registers

* API for FPGA registers

Signed-off-by: Serhii Iliushyk <sil-plv@napatech.com>
---
 .../NT200A02_U23_Si5340_adr0_v5-Registers.h   |  752 +++++++++++
 drivers/net/ntnic/meson.build                 |   16 +
 .../clock_profiles/nthw_fpga_clk9563.c        |   51 +
 .../clock_profiles/nthw_fpga_clk9563.h        |    9 +
 .../nthw/core/nt200a0x/nthw_fpga_nt200a0x.c   |  107 ++
 .../nthw/core/nt200a0x/nthw_fpga_nt200a0x.h   |    9 +
 .../core/nt200a0x/reset/nthw_fpga_rst9563.c   |  258 ++++
 .../core/nt200a0x/reset/nthw_fpga_rst9563.h   |    9 +
 .../nt200a0x/reset/nthw_fpga_rst_nt200a0x.c   |  729 ++++++++++
 .../nt200a0x/reset/nthw_fpga_rst_nt200a0x.h   |    9 +
 drivers/net/ntnic/nthw/core/nthw_fpga.c       |  888 +++++++++++++
 drivers/net/ntnic/nthw/core/nthw_fpga_rst.c   |   10 +
 drivers/net/ntnic/nthw/core/nthw_hif.c        |  312 +++++
 drivers/net/ntnic/nthw/core/nthw_iic.c        |  529 ++++++++
 .../net/ntnic/nthw/core/nthw_mac_pcs_xxv.c    | 1169 +++++++++++++++++
 drivers/net/ntnic/nthw/core/nthw_pcie3.c      |  270 ++++
 drivers/net/ntnic/nthw/core/nthw_sdc.c        |  176 +++
 drivers/net/ntnic/nthw/core/nthw_si5340.c     |  205 +++
 drivers/net/ntnic/nthw/core/nthw_spi_v3.c     |  356 +++++
 drivers/net/ntnic/nthw/core/nthw_spim.c       |  121 ++
 drivers/net/ntnic/nthw/core/nthw_spis.c       |  129 ++
 drivers/net/ntnic/nthw/core/nthw_tsm.c        |  167 +++
 22 files changed, 6281 insertions(+)
 create mode 100644 drivers/net/ntnic/include/NT200A02_U23_Si5340_adr0_v5-Registers.h
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.h
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.h
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.h
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
 create mode 100644 drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.h
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_fpga_rst.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_hif.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_iic.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcie3.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_sdc.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_si5340.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_spi_v3.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_spim.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_spis.c
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_tsm.c

diff --git a/drivers/net/ntnic/include/NT200A02_U23_Si5340_adr0_v5-Registers.h b/drivers/net/ntnic/include/NT200A02_U23_Si5340_adr0_v5-Registers.h
new file mode 100644
index 0000000000..c4185c77ff
--- /dev/null
+++ b/drivers/net/ntnic/include/NT200A02_U23_Si5340_adr0_v5-Registers.h
@@ -0,0 +1,752 @@
+/*
+ * Si5340 Rev D Configuration Register Export Header File
+ *
+ * This file represents a series of Silicon Labs Si5340 Rev D
+ * register writes that can be performed to load a single configuration
+ * on a device. It was created by a Silicon Labs ClockBuilder Pro
+ * export tool.
+ *
+ * Part:		                                       Si5340 Rev D
+ * Design ID:                                          05
+ * Includes Pre/Post Download Control Register Writes: Yes
+ * Created By:                                         ClockBuilder Pro v2.28.1 [2018-09-24]
+ * Timestamp:                                          2018-11-14 16:20:29 GMT+01:00
+ *
+ * A complete design report corresponding to this export is included at the end
+ * of this header file.
+ *
+ */
+
+#ifndef SI5340_REVD_REG_CONFIG_HEADER
+#define SI5340_REVD_REG_CONFIG_HEADER
+
+#define SI5340_REVD_REG_CONFIG_NUM_REGS 326
+
+typedef struct {
+	unsigned int address;	/* 16-bit register address */
+	unsigned char value;	/* 8-bit register data */
+
+} si5340_revd_register_t;
+
+static const si5340_revd_register_t si5340_revd_registers[SI5340_REVD_REG_CONFIG_NUM_REGS] = {
+	/* Start configuration preamble */
+	{ 0x0B24, 0xC0 },
+	{ 0x0B25, 0x00 },
+	/* Rev D stuck divider fix */
+	{ 0x0502, 0x01 },
+	{ 0x0505, 0x03 },
+	{ 0x0957, 0x17 },
+	{ 0x0B4E, 0x1A },
+	/* End configuration preamble */
+
+	/* Delay 300 msec */
+	/*    Delay is worst case time for device to complete any calibration */
+	/*    that is running due to device state change previous to this script */
+	/*    being processed. */
+
+	/* Start configuration registers */
+	{ 0x0006, 0x00 },
+	{ 0x0007, 0x00 },
+	{ 0x0008, 0x00 },
+	{ 0x000B, 0x74 },
+	{ 0x0017, 0xF0 },
+	{ 0x0018, 0xFF },
+	{ 0x0021, 0x0F },
+	{ 0x0022, 0x00 },
+	{ 0x002B, 0x0A },
+	{ 0x002C, 0x20 },
+	{ 0x002D, 0x00 },
+	{ 0x002E, 0x00 },
+	{ 0x002F, 0x00 },
+	{ 0x0030, 0x00 },
+	{ 0x0031, 0x00 },
+	{ 0x0032, 0x00 },
+	{ 0x0033, 0x00 },
+	{ 0x0034, 0x00 },
+	{ 0x0035, 0x00 },
+	{ 0x0036, 0x00 },
+	{ 0x0037, 0x00 },
+	{ 0x0038, 0x00 },
+	{ 0x0039, 0x00 },
+	{ 0x003A, 0x00 },
+	{ 0x003B, 0x00 },
+	{ 0x003C, 0x00 },
+	{ 0x003D, 0x00 },
+	{ 0x0041, 0x00 },
+	{ 0x0042, 0x00 },
+	{ 0x0043, 0x00 },
+	{ 0x0044, 0x00 },
+	{ 0x009E, 0x00 },
+	{ 0x0102, 0x01 },
+	{ 0x0112, 0x02 },
+	{ 0x0113, 0x09 },
+	{ 0x0114, 0x3E },
+	{ 0x0115, 0x19 },
+	{ 0x0117, 0x06 },
+	{ 0x0118, 0x09 },
+	{ 0x0119, 0x3E },
+	{ 0x011A, 0x18 },
+	{ 0x0126, 0x06 },
+	{ 0x0127, 0x09 },
+	{ 0x0128, 0x3E },
+	{ 0x0129, 0x18 },
+	{ 0x012B, 0x06 },
+	{ 0x012C, 0x09 },
+	{ 0x012D, 0x3E },
+	{ 0x012E, 0x1A },
+	{ 0x013F, 0x00 },
+	{ 0x0140, 0x00 },
+	{ 0x0141, 0x40 },
+	{ 0x0206, 0x00 },
+	{ 0x0208, 0x00 },
+	{ 0x0209, 0x00 },
+	{ 0x020A, 0x00 },
+	{ 0x020B, 0x00 },
+	{ 0x020C, 0x00 },
+	{ 0x020D, 0x00 },
+	{ 0x020E, 0x00 },
+	{ 0x020F, 0x00 },
+	{ 0x0210, 0x00 },
+	{ 0x0211, 0x00 },
+	{ 0x0212, 0x00 },
+	{ 0x0213, 0x00 },
+	{ 0x0214, 0x00 },
+	{ 0x0215, 0x00 },
+	{ 0x0216, 0x00 },
+	{ 0x0217, 0x00 },
+	{ 0x0218, 0x00 },
+	{ 0x0219, 0x00 },
+	{ 0x021A, 0x00 },
+	{ 0x021B, 0x00 },
+	{ 0x021C, 0x00 },
+	{ 0x021D, 0x00 },
+	{ 0x021E, 0x00 },
+	{ 0x021F, 0x00 },
+	{ 0x0220, 0x00 },
+	{ 0x0221, 0x00 },
+	{ 0x0222, 0x00 },
+	{ 0x0223, 0x00 },
+	{ 0x0224, 0x00 },
+	{ 0x0225, 0x00 },
+	{ 0x0226, 0x00 },
+	{ 0x0227, 0x00 },
+	{ 0x0228, 0x00 },
+	{ 0x0229, 0x00 },
+	{ 0x022A, 0x00 },
+	{ 0x022B, 0x00 },
+	{ 0x022C, 0x00 },
+	{ 0x022D, 0x00 },
+	{ 0x022E, 0x00 },
+	{ 0x022F, 0x00 },
+	{ 0x0235, 0x00 },
+	{ 0x0236, 0x00 },
+	{ 0x0237, 0x00 },
+	{ 0x0238, 0xA6 },
+	{ 0x0239, 0x8B },
+	{ 0x023A, 0x00 },
+	{ 0x023B, 0x00 },
+	{ 0x023C, 0x00 },
+	{ 0x023D, 0x00 },
+	{ 0x023E, 0x80 },
+	{ 0x0250, 0x03 },
+	{ 0x0251, 0x00 },
+	{ 0x0252, 0x00 },
+	{ 0x0253, 0x00 },
+	{ 0x0254, 0x00 },
+	{ 0x0255, 0x00 },
+	{ 0x025C, 0x00 },
+	{ 0x025D, 0x00 },
+	{ 0x025E, 0x00 },
+	{ 0x025F, 0x00 },
+	{ 0x0260, 0x00 },
+	{ 0x0261, 0x00 },
+	{ 0x026B, 0x30 },
+	{ 0x026C, 0x35 },
+	{ 0x026D, 0x00 },
+	{ 0x026E, 0x00 },
+	{ 0x026F, 0x00 },
+	{ 0x0270, 0x00 },
+	{ 0x0271, 0x00 },
+	{ 0x0272, 0x00 },
+	{ 0x0302, 0x00 },
+	{ 0x0303, 0x00 },
+	{ 0x0304, 0x00 },
+	{ 0x0305, 0x00 },
+	{ 0x0306, 0x0D },
+	{ 0x0307, 0x00 },
+	{ 0x0308, 0x00 },
+	{ 0x0309, 0x00 },
+	{ 0x030A, 0x00 },
+	{ 0x030B, 0x80 },
+	{ 0x030C, 0x00 },
+	{ 0x030D, 0x00 },
+	{ 0x030E, 0x00 },
+	{ 0x030F, 0x00 },
+	{ 0x0310, 0x61 },
+	{ 0x0311, 0x08 },
+	{ 0x0312, 0x00 },
+	{ 0x0313, 0x00 },
+	{ 0x0314, 0x00 },
+	{ 0x0315, 0x00 },
+	{ 0x0316, 0x80 },
+	{ 0x0317, 0x00 },
+	{ 0x0318, 0x00 },
+	{ 0x0319, 0x00 },
+	{ 0x031A, 0x00 },
+	{ 0x031B, 0xD0 },
+	{ 0x031C, 0x1A },
+	{ 0x031D, 0x00 },
+	{ 0x031E, 0x00 },
+	{ 0x031F, 0x00 },
+	{ 0x0320, 0x00 },
+	{ 0x0321, 0xA0 },
+	{ 0x0322, 0x00 },
+	{ 0x0323, 0x00 },
+	{ 0x0324, 0x00 },
+	{ 0x0325, 0x00 },
+	{ 0x0326, 0x00 },
+	{ 0x0327, 0x00 },
+	{ 0x0328, 0x00 },
+	{ 0x0329, 0x00 },
+	{ 0x032A, 0x00 },
+	{ 0x032B, 0x00 },
+	{ 0x032C, 0x00 },
+	{ 0x032D, 0x00 },
+	{ 0x0338, 0x00 },
+	{ 0x0339, 0x1F },
+	{ 0x033B, 0x00 },
+	{ 0x033C, 0x00 },
+	{ 0x033D, 0x00 },
+	{ 0x033E, 0x00 },
+	{ 0x033F, 0x00 },
+	{ 0x0340, 0x00 },
+	{ 0x0341, 0x00 },
+	{ 0x0342, 0x00 },
+	{ 0x0343, 0x00 },
+	{ 0x0344, 0x00 },
+	{ 0x0345, 0x00 },
+	{ 0x0346, 0x00 },
+	{ 0x0347, 0x00 },
+	{ 0x0348, 0x00 },
+	{ 0x0349, 0x00 },
+	{ 0x034A, 0x00 },
+	{ 0x034B, 0x00 },
+	{ 0x034C, 0x00 },
+	{ 0x034D, 0x00 },
+	{ 0x034E, 0x00 },
+	{ 0x034F, 0x00 },
+	{ 0x0350, 0x00 },
+	{ 0x0351, 0x00 },
+	{ 0x0352, 0x00 },
+	{ 0x0359, 0x00 },
+	{ 0x035A, 0x00 },
+	{ 0x035B, 0x00 },
+	{ 0x035C, 0x00 },
+	{ 0x035D, 0x00 },
+	{ 0x035E, 0x00 },
+	{ 0x035F, 0x00 },
+	{ 0x0360, 0x00 },
+	{ 0x0802, 0x00 },
+	{ 0x0803, 0x00 },
+	{ 0x0804, 0x00 },
+	{ 0x0805, 0x00 },
+	{ 0x0806, 0x00 },
+	{ 0x0807, 0x00 },
+	{ 0x0808, 0x00 },
+	{ 0x0809, 0x00 },
+	{ 0x080A, 0x00 },
+	{ 0x080B, 0x00 },
+	{ 0x080C, 0x00 },
+	{ 0x080D, 0x00 },
+	{ 0x080E, 0x00 },
+	{ 0x080F, 0x00 },
+	{ 0x0810, 0x00 },
+	{ 0x0811, 0x00 },
+	{ 0x0812, 0x00 },
+	{ 0x0813, 0x00 },
+	{ 0x0814, 0x00 },
+	{ 0x0815, 0x00 },
+	{ 0x0816, 0x00 },
+	{ 0x0817, 0x00 },
+	{ 0x0818, 0x00 },
+	{ 0x0819, 0x00 },
+	{ 0x081A, 0x00 },
+	{ 0x081B, 0x00 },
+	{ 0x081C, 0x00 },
+	{ 0x081D, 0x00 },
+	{ 0x081E, 0x00 },
+	{ 0x081F, 0x00 },
+	{ 0x0820, 0x00 },
+	{ 0x0821, 0x00 },
+	{ 0x0822, 0x00 },
+	{ 0x0823, 0x00 },
+	{ 0x0824, 0x00 },
+	{ 0x0825, 0x00 },
+	{ 0x0826, 0x00 },
+	{ 0x0827, 0x00 },
+	{ 0x0828, 0x00 },
+	{ 0x0829, 0x00 },
+	{ 0x082A, 0x00 },
+	{ 0x082B, 0x00 },
+	{ 0x082C, 0x00 },
+	{ 0x082D, 0x00 },
+	{ 0x082E, 0x00 },
+	{ 0x082F, 0x00 },
+	{ 0x0830, 0x00 },
+	{ 0x0831, 0x00 },
+	{ 0x0832, 0x00 },
+	{ 0x0833, 0x00 },
+	{ 0x0834, 0x00 },
+	{ 0x0835, 0x00 },
+	{ 0x0836, 0x00 },
+	{ 0x0837, 0x00 },
+	{ 0x0838, 0x00 },
+	{ 0x0839, 0x00 },
+	{ 0x083A, 0x00 },
+	{ 0x083B, 0x00 },
+	{ 0x083C, 0x00 },
+	{ 0x083D, 0x00 },
+	{ 0x083E, 0x00 },
+	{ 0x083F, 0x00 },
+	{ 0x0840, 0x00 },
+	{ 0x0841, 0x00 },
+	{ 0x0842, 0x00 },
+	{ 0x0843, 0x00 },
+	{ 0x0844, 0x00 },
+	{ 0x0845, 0x00 },
+	{ 0x0846, 0x00 },
+	{ 0x0847, 0x00 },
+	{ 0x0848, 0x00 },
+	{ 0x0849, 0x00 },
+	{ 0x084A, 0x00 },
+	{ 0x084B, 0x00 },
+	{ 0x084C, 0x00 },
+	{ 0x084D, 0x00 },
+	{ 0x084E, 0x00 },
+	{ 0x084F, 0x00 },
+	{ 0x0850, 0x00 },
+	{ 0x0851, 0x00 },
+	{ 0x0852, 0x00 },
+	{ 0x0853, 0x00 },
+	{ 0x0854, 0x00 },
+	{ 0x0855, 0x00 },
+	{ 0x0856, 0x00 },
+	{ 0x0857, 0x00 },
+	{ 0x0858, 0x00 },
+	{ 0x0859, 0x00 },
+	{ 0x085A, 0x00 },
+	{ 0x085B, 0x00 },
+	{ 0x085C, 0x00 },
+	{ 0x085D, 0x00 },
+	{ 0x085E, 0x00 },
+	{ 0x085F, 0x00 },
+	{ 0x0860, 0x00 },
+	{ 0x0861, 0x00 },
+	{ 0x090E, 0x02 },
+	{ 0x091C, 0x04 },
+	{ 0x0943, 0x00 },
+	{ 0x0949, 0x00 },
+	{ 0x094A, 0x00 },
+	{ 0x094E, 0x49 },
+	{ 0x094F, 0x02 },
+	{ 0x095E, 0x00 },
+	{ 0x0A02, 0x00 },
+	{ 0x0A03, 0x07 },
+	{ 0x0A04, 0x01 },
+	{ 0x0A05, 0x07 },
+	{ 0x0A14, 0x00 },
+	{ 0x0A1A, 0x00 },
+	{ 0x0A20, 0x00 },
+	{ 0x0A26, 0x00 },
+	{ 0x0B44, 0x0F },
+	{ 0x0B4A, 0x08 },
+	{ 0x0B57, 0x0E },
+	{ 0x0B58, 0x01 },
+	/* End configuration registers */
+
+	/* Start configuration postamble */
+	{ 0x001C, 0x01 },
+	{ 0x0B24, 0xC3 },
+	{ 0x0B25, 0x02 },
+	/* End configuration postamble */
+};
+
+/*
+ * Design Report
+ *
+ * Overview
+ * ========
+ * Part:               Si5340AB Rev D
+ * Project File:       P:\Hardware\NT
+ * Adapters\NT200A02\design\Clock_syn_design\NT200A02_U23_Si5340_adr0_v5.slabtimeproj Design ID: 05
+ * Created By:         ClockBuilder Pro v2.28.1 [2018-09-24]
+ * Timestamp:          2018-11-14 16:20:29 GMT+01:00
+ *
+ * Design Rule Check
+ * =================
+ * Errors:
+ * - No errors
+ *
+ * Warnings:
+ * - No warnings
+ *
+ * Device Grade
+ * ============
+ * Maximum Output Frequency: 257.8125 MHz
+ * Frequency Synthesis Mode: Fractional
+ * Frequency Plan Grade:     B
+ * Minimum Base OPN:         Si5340B*
+ *
+ * Base       Output Clock         Supported Frequency Synthesis Modes
+ * OPN Grade  Frequency Range      (Typical Jitter)
+ * ---------  -------------------  --------------------------------------------
+ * Si5340A    100 Hz to 1.028 GHz  Integer (< 100 fs) and fractional (< 150 fs)
+ * Si5340B*   100 Hz to 350 MHz    "
+ * Si5340C    100 Hz to 1.028 GHz  Integer only (< 100 fs)
+ * Si5340D    100 Hz to 350 MHz    "
+ *
+ * * Based on your calculated frequency plan, a Si5340B grade device is
+ * sufficient for your design. For more in-system configuration flexibility
+ * (higher frequencies and/or to enable fractional synthesis), consider
+ * selecting device grade Si5340A when specifying an ordering part number (OPN)
+ * for your application. See the datasheet Ordering Guide for more information.
+ *
+ * Design
+ * ======
+ * Host Interface:
+ *    I/O Power Supply: VDD (Core)
+ *    SPI Mode: 3-Wire
+ *    I2C Address Range: 116d to 119d / 0x74 to 0x77 (selected via A0/A1 pins)
+ *
+ * Inputs:
+ *    XAXB: 48 MHz
+ *          Crystal Mode
+ *     IN0: Unused
+ *     IN1: Unused
+ *     IN2: Unused
+ *   FB_IN: Unused
+ *
+ * Outputs:
+ *    OUT0: 100 MHz
+ *          Enabled, LVDS 1.8 V
+ *    OUT1: 257.8125 MHz [ 257 + 13/16 MHz ]
+ *          Enabled, LVDS 1.8 V
+ *    OUT2: 257.8125 MHz [ 257 + 13/16 MHz ]
+ *          Enabled, LVDS 1.8 V
+ *    OUT3: 156.25 MHz [ 156 + 1/4 MHz ]
+ *          Enabled, LVDS 1.8 V
+ *
+ * Frequency Plan
+ * ==============
+ * Priority: OUT1 is lowest jitter output
+ *
+ * Fpfd = 48 MHz
+ * Fvco = 13.40625 GHz [ 13 + 13/32 GHz ]
+ * Fms0 = 515.625 MHz [ 515 + 5/8 MHz ]
+ * Fms1 = 800 MHz
+ * Fms2 = 312.5 MHz [ 312 + 1/2 MHz ]
+ *
+ * P dividers:
+ *    P0  = Unused
+ *    P1  = Unused
+ *    P2  = Unused
+ *    P3  = Unused
+ *    Pxaxb = 1
+ *
+ * M = 279.296875 [ 279 + 19/64 ]
+ * N dividers:
+ *    N0:
+ *       Value: 26
+ *       Skew:  0.000 s
+ *       OUT1: 257.8125 MHz [ 257 + 13/16 MHz ]
+ *       OUT2: 257.8125 MHz [ 257 + 13/16 MHz ]
+ *    N1:
+ *       Value: 16.7578125 [ 16 + 97/128 ]
+ *       Skew:  0.000 s
+ *       OUT0: 100 MHz
+ *    N2:
+ *       Value: 42.9 [ 42 + 9/10 ]
+ *       Skew:  0.000 s
+ *       OUT3: 156.25 MHz [ 156 + 1/4 MHz ]
+ *    N3:
+ *       Unused
+ *
+ * R dividers:
+ *    R0 = 8
+ *    R1 = 2
+ *    R2 = 2
+ *    R3 = 2
+ *
+ * Dividers listed above show effective values. These values are translated to register settings by
+ * ClockBuilder Pro. For the actual register values, see below. Refer to the Family Reference
+ * Manual for information on registers related to frequency plan.
+ *
+ * Digitally Controlled Oscillator (DCO)
+ * =====================================
+ * Mode: FINC/FDEC
+ *
+ * N0: DCO Disabled
+ *
+ * N1: DCO Disabled
+ *
+ * N2: DCO Disabled
+ *
+ * N3: DCO Disabled
+ *
+ * Estimated Power & Junction Temperature
+ * ======================================
+ * Assumptions:
+ *
+ * Revision: D
+ * VDD:      1.8 V
+ * Ta:       70 °C
+ * Airflow:  None
+ *
+ * Total Power: 767 mW, On Chip Power: 743 mW, Tj: 87 °C
+ *
+ *            Frequency  Format   Voltage   Current     Power
+ *         ------------  ------  --------  --------  --------
+ * VDD                              1.8 V  146.3 mA    263 mW
+ * VDDA                             3.3 V  117.4 mA    387 mW
+ * VDDO0        100 MHz  LVDS       1.8 V   15.6 mA     28 mW
+ * VDDO1   257.8125 MHz  LVDS       1.8 V   16.6 mA     30 mW
+ * VDDO2   257.8125 MHz  LVDS       1.8 V   16.6 mA     30 mW
+ * VDDO3     156.25 MHz  LVDS       1.8 V   15.9 mA     29 mW
+ *                                         --------  --------
+ *                                  Total  328.4 mA    767 mW
+ *
+ * Note:
+ *
+ * -Total power includes on- and off-chip power. This is a typical value and estimate only.
+ * -Use an EVB for a more exact power measurement
+ * -On-chip power excludes power dissipated in external terminations.
+ * -Tj is junction temperature. Tj must be less than 125 °C (on Si5340 Revision D) for device to
+ * comply with datasheet specifications.
+ *
+ * Settings
+ * ========
+ *
+ * Location      Setting Name         Decimal Value      Hex Value
+ * ------------  -------------------  -----------------  -----------------
+ * 0x0006[23:0]  TOOL_VERSION         0                  0x000000
+ * 0x000B[6:0]   I2C_ADDR             116                0x74
+ * 0x0017[0]     SYSINCAL_INTR_MSK    0                  0x0
+ * 0x0017[1]     LOSXAXB_INTR_MSK     0                  0x0
+ * 0x0017[2]     LOSREF_INTR_MSK      0                  0x0
+ * 0x0017[3]     LOL_INTR_MSK         0                  0x0
+ * 0x0017[5]     SMB_TMOUT_INTR_MSK   1                  0x1
+ * 0x0018[3:0]   LOSIN_INTR_MSK       15                 0xF
+ * 0x0021[0]     IN_SEL_REGCTRL       1                  0x1
+ * 0x0021[2:1]   IN_SEL               3                  0x3
+ * 0x0022[1]     OE                   0                  0x0
+ * 0x002B[3]     SPI_3WIRE            1                  0x1
+ * 0x002B[5]     AUTO_NDIV_UPDATE     0                  0x0
+ * 0x002C[3:0]   LOS_EN               0                  0x0
+ * 0x002C[4]     LOSXAXB_DIS          0                  0x0
+ * 0x002D[1:0]   LOS0_VAL_TIME        0                  0x0
+ * 0x002D[3:2]   LOS1_VAL_TIME        0                  0x0
+ * 0x002D[5:4]   LOS2_VAL_TIME        0                  0x0
+ * 0x002D[7:6]   LOS3_VAL_TIME        0                  0x0
+ * 0x002E[15:0]  LOS0_TRG_THR         0                  0x0000
+ * 0x0030[15:0]  LOS1_TRG_THR         0                  0x0000
+ * 0x0032[15:0]  LOS2_TRG_THR         0                  0x0000
+ * 0x0034[15:0]  LOS3_TRG_THR         0                  0x0000
+ * 0x0036[15:0]  LOS0_CLR_THR         0                  0x0000
+ * 0x0038[15:0]  LOS1_CLR_THR         0                  0x0000
+ * 0x003A[15:0]  LOS2_CLR_THR         0                  0x0000
+ * 0x003C[15:0]  LOS3_CLR_THR         0                  0x0000
+ * 0x0041[4:0]   LOS0_DIV_SEL         0                  0x00
+ * 0x0042[4:0]   LOS1_DIV_SEL         0                  0x00
+ * 0x0043[4:0]   LOS2_DIV_SEL         0                  0x00
+ * 0x0044[4:0]   LOS3_DIV_SEL         0                  0x00
+ * 0x009E[7:4]   LOL_SET_THR          0                  0x0
+ * 0x0102[0]     OUTALL_DISABLE_LOW   1                  0x1
+ * 0x0112[0]     OUT0_PDN             0                  0x0
+ * 0x0112[1]     OUT0_OE              1                  0x1
+ * 0x0112[2]     OUT0_RDIV_FORCE2     0                  0x0
+ * 0x0113[2:0]   OUT0_FORMAT          1                  0x1
+ * 0x0113[3]     OUT0_SYNC_EN         1                  0x1
+ * 0x0113[5:4]   OUT0_DIS_STATE       0                  0x0
+ * 0x0113[7:6]   OUT0_CMOS_DRV        0                  0x0
+ * 0x0114[3:0]   OUT0_CM              14                 0xE
+ * 0x0114[6:4]   OUT0_AMPL            3                  0x3
+ * 0x0115[2:0]   OUT0_MUX_SEL         1                  0x1
+ * 0x0115[5:4]   OUT0_VDD_SEL         1                  0x1
+ * 0x0115[3]     OUT0_VDD_SEL_EN      1                  0x1
+ * 0x0115[7:6]   OUT0_INV             0                  0x0
+ * 0x0117[0]     OUT1_PDN             0                  0x0
+ * 0x0117[1]     OUT1_OE              1                  0x1
+ * 0x0117[2]     OUT1_RDIV_FORCE2     1                  0x1
+ * 0x0118[2:0]   OUT1_FORMAT          1                  0x1
+ * 0x0118[3]     OUT1_SYNC_EN         1                  0x1
+ * 0x0118[5:4]   OUT1_DIS_STATE       0                  0x0
+ * 0x0118[7:6]   OUT1_CMOS_DRV        0                  0x0
+ * 0x0119[3:0]   OUT1_CM              14                 0xE
+ * 0x0119[6:4]   OUT1_AMPL            3                  0x3
+ * 0x011A[2:0]   OUT1_MUX_SEL         0                  0x0
+ * 0x011A[5:4]   OUT1_VDD_SEL         1                  0x1
+ * 0x011A[3]     OUT1_VDD_SEL_EN      1                  0x1
+ * 0x011A[7:6]   OUT1_INV             0                  0x0
+ * 0x0126[0]     OUT2_PDN             0                  0x0
+ * 0x0126[1]     OUT2_OE              1                  0x1
+ * 0x0126[2]     OUT2_RDIV_FORCE2     1                  0x1
+ * 0x0127[2:0]   OUT2_FORMAT          1                  0x1
+ * 0x0127[3]     OUT2_SYNC_EN         1                  0x1
+ * 0x0127[5:4]   OUT2_DIS_STATE       0                  0x0
+ * 0x0127[7:6]   OUT2_CMOS_DRV        0                  0x0
+ * 0x0128[3:0]   OUT2_CM              14                 0xE
+ * 0x0128[6:4]   OUT2_AMPL            3                  0x3
+ * 0x0129[2:0]   OUT2_MUX_SEL         0                  0x0
+ * 0x0129[5:4]   OUT2_VDD_SEL         1                  0x1
+ * 0x0129[3]     OUT2_VDD_SEL_EN      1                  0x1
+ * 0x0129[7:6]   OUT2_INV             0                  0x0
+ * 0x012B[0]     OUT3_PDN             0                  0x0
+ * 0x012B[1]     OUT3_OE              1                  0x1
+ * 0x012B[2]     OUT3_RDIV_FORCE2     1                  0x1
+ * 0x012C[2:0]   OUT3_FORMAT          1                  0x1
+ * 0x012C[3]     OUT3_SYNC_EN         1                  0x1
+ * 0x012C[5:4]   OUT3_DIS_STATE       0                  0x0
+ * 0x012C[7:6]   OUT3_CMOS_DRV        0                  0x0
+ * 0x012D[3:0]   OUT3_CM              14                 0xE
+ * 0x012D[6:4]   OUT3_AMPL            3                  0x3
+ * 0x012E[2:0]   OUT3_MUX_SEL         2                  0x2
+ * 0x012E[5:4]   OUT3_VDD_SEL         1                  0x1
+ * 0x012E[3]     OUT3_VDD_SEL_EN      1                  0x1
+ * 0x012E[7:6]   OUT3_INV             0                  0x0
+ * 0x013F[11:0]  OUTX_ALWAYS_ON       0                  0x000
+ * 0x0141[5]     OUT_DIS_LOL_MSK      0                  0x0
+ * 0x0141[7]     OUT_DIS_MSK_LOS_PFD  0                  0x0
+ * 0x0206[1:0]   PXAXB                0                  0x0
+ * 0x0208[47:0]  P0                   0                  0x000000000000
+ * 0x020E[31:0]  P0_SET               0                  0x00000000
+ * 0x0212[47:0]  P1                   0                  0x000000000000
+ * 0x0218[31:0]  P1_SET               0                  0x00000000
+ * 0x021C[47:0]  P2                   0                  0x000000000000
+ * 0x0222[31:0]  P2_SET               0                  0x00000000
+ * 0x0226[47:0]  P3                   0                  0x000000000000
+ * 0x022C[31:0]  P3_SET               0                  0x00000000
+ * 0x0235[43:0]  M_NUM                599785472000       0x08BA6000000
+ * 0x023B[31:0]  M_DEN                2147483648         0x80000000
+ * 0x0250[23:0]  R0_REG               3                  0x000003
+ * 0x0253[23:0]  R1_REG               0                  0x000000
+ * 0x025C[23:0]  R2_REG               0                  0x000000
+ * 0x025F[23:0]  R3_REG               0                  0x000000
+ * 0x026B[7:0]   DESIGN_ID0           48                 0x30
+ * 0x026C[7:0]   DESIGN_ID1           53                 0x35
+ * 0x026D[7:0]   DESIGN_ID2           0                  0x00
+ * 0x026E[7:0]   DESIGN_ID3           0                  0x00
+ * 0x026F[7:0]   DESIGN_ID4           0                  0x00
+ * 0x0270[7:0]   DESIGN_ID5           0                  0x00
+ * 0x0271[7:0]   DESIGN_ID6           0                  0x00
+ * 0x0272[7:0]   DESIGN_ID7           0                  0x00
+ * 0x0302[43:0]  N0_NUM               55834574848        0x00D00000000
+ * 0x0308[31:0]  N0_DEN               2147483648         0x80000000
+ * 0x030C[0]     N0_UPDATE            0                  0x0
+ * 0x030D[43:0]  N1_NUM               35987128320        0x00861000000
+ * 0x0313[31:0]  N1_DEN               2147483648         0x80000000
+ * 0x0317[0]     N1_UPDATE            0                  0x0
+ * 0x0318[43:0]  N2_NUM               115158810624       0x01AD0000000
+ * 0x031E[31:0]  N2_DEN               2684354560         0xA0000000
+ * 0x0322[0]     N2_UPDATE            0                  0x0
+ * 0x0323[43:0]  N3_NUM               0                  0x00000000000
+ * 0x0329[31:0]  N3_DEN               0                  0x00000000
+ * 0x032D[0]     N3_UPDATE            0                  0x0
+ * 0x0338[1]     N_UPDATE             0                  0x0
+ * 0x0339[4:0]   N_FSTEP_MSK          31                 0x1F
+ * 0x033B[43:0]  N0_FSTEPW            0                  0x00000000000
+ * 0x0341[43:0]  N1_FSTEPW            0                  0x00000000000
+ * 0x0347[43:0]  N2_FSTEPW            0                  0x00000000000
+ * 0x034D[43:0]  N3_FSTEPW            0                  0x00000000000
+ * 0x0359[15:0]  N0_DELAY             0                  0x0000
+ * 0x035B[15:0]  N1_DELAY             0                  0x0000
+ * 0x035D[15:0]  N2_DELAY             0                  0x0000
+ * 0x035F[15:0]  N3_DELAY             0                  0x0000
+ * 0x0802[15:0]  FIXREGSA0            0                  0x0000
+ * 0x0804[7:0]   FIXREGSD0            0                  0x00
+ * 0x0805[15:0]  FIXREGSA1            0                  0x0000
+ * 0x0807[7:0]   FIXREGSD1            0                  0x00
+ * 0x0808[15:0]  FIXREGSA2            0                  0x0000
+ * 0x080A[7:0]   FIXREGSD2            0                  0x00
+ * 0x080B[15:0]  FIXREGSA3            0                  0x0000
+ * 0x080D[7:0]   FIXREGSD3            0                  0x00
+ * 0x080E[15:0]  FIXREGSA4            0                  0x0000
+ * 0x0810[7:0]   FIXREGSD4            0                  0x00
+ * 0x0811[15:0]  FIXREGSA5            0                  0x0000
+ * 0x0813[7:0]   FIXREGSD5            0                  0x00
+ * 0x0814[15:0]  FIXREGSA6            0                  0x0000
+ * 0x0816[7:0]   FIXREGSD6            0                  0x00
+ * 0x0817[15:0]  FIXREGSA7            0                  0x0000
+ * 0x0819[7:0]   FIXREGSD7            0                  0x00
+ * 0x081A[15:0]  FIXREGSA8            0                  0x0000
+ * 0x081C[7:0]   FIXREGSD8            0                  0x00
+ * 0x081D[15:0]  FIXREGSA9            0                  0x0000
+ * 0x081F[7:0]   FIXREGSD9            0                  0x00
+ * 0x0820[15:0]  FIXREGSA10           0                  0x0000
+ * 0x0822[7:0]   FIXREGSD10           0                  0x00
+ * 0x0823[15:0]  FIXREGSA11           0                  0x0000
+ * 0x0825[7:0]   FIXREGSD11           0                  0x00
+ * 0x0826[15:0]  FIXREGSA12           0                  0x0000
+ * 0x0828[7:0]   FIXREGSD12           0                  0x00
+ * 0x0829[15:0]  FIXREGSA13           0                  0x0000
+ * 0x082B[7:0]   FIXREGSD13           0                  0x00
+ * 0x082C[15:0]  FIXREGSA14           0                  0x0000
+ * 0x082E[7:0]   FIXREGSD14           0                  0x00
+ * 0x082F[15:0]  FIXREGSA15           0                  0x0000
+ * 0x0831[7:0]   FIXREGSD15           0                  0x00
+ * 0x0832[15:0]  FIXREGSA16           0                  0x0000
+ * 0x0834[7:0]   FIXREGSD16           0                  0x00
+ * 0x0835[15:0]  FIXREGSA17           0                  0x0000
+ * 0x0837[7:0]   FIXREGSD17           0                  0x00
+ * 0x0838[15:0]  FIXREGSA18           0                  0x0000
+ * 0x083A[7:0]   FIXREGSD18           0                  0x00
+ * 0x083B[15:0]  FIXREGSA19           0                  0x0000
+ * 0x083D[7:0]   FIXREGSD19           0                  0x00
+ * 0x083E[15:0]  FIXREGSA20           0                  0x0000
+ * 0x0840[7:0]   FIXREGSD20           0                  0x00
+ * 0x0841[15:0]  FIXREGSA21           0                  0x0000
+ * 0x0843[7:0]   FIXREGSD21           0                  0x00
+ * 0x0844[15:0]  FIXREGSA22           0                  0x0000
+ * 0x0846[7:0]   FIXREGSD22           0                  0x00
+ * 0x0847[15:0]  FIXREGSA23           0                  0x0000
+ * 0x0849[7:0]   FIXREGSD23           0                  0x00
+ * 0x084A[15:0]  FIXREGSA24           0                  0x0000
+ * 0x084C[7:0]   FIXREGSD24           0                  0x00
+ * 0x084D[15:0]  FIXREGSA25           0                  0x0000
+ * 0x084F[7:0]   FIXREGSD25           0                  0x00
+ * 0x0850[15:0]  FIXREGSA26           0                  0x0000
+ * 0x0852[7:0]   FIXREGSD26           0                  0x00
+ * 0x0853[15:0]  FIXREGSA27           0                  0x0000
+ * 0x0855[7:0]   FIXREGSD27           0                  0x00
+ * 0x0856[15:0]  FIXREGSA28           0                  0x0000
+ * 0x0858[7:0]   FIXREGSD28           0                  0x00
+ * 0x0859[15:0]  FIXREGSA29           0                  0x0000
+ * 0x085B[7:0]   FIXREGSD29           0                  0x00
+ * 0x085C[15:0]  FIXREGSA30           0                  0x0000
+ * 0x085E[7:0]   FIXREGSD30           0                  0x00
+ * 0x085F[15:0]  FIXREGSA31           0                  0x0000
+ * 0x0861[7:0]   FIXREGSD31           0                  0x00
+ * 0x090E[0]     XAXB_EXTCLK_EN       0                  0x0
+ * 0x090E[1]     XAXB_PDNB            1                  0x1
+ * 0x091C[2:0]   ZDM_EN               4                  0x4
+ * 0x0943[0]     IO_VDD_SEL           0                  0x0
+ * 0x0949[3:0]   IN_EN                0                  0x0
+ * 0x0949[7:4]   IN_PULSED_CMOS_EN    0                  0x0
+ * 0x094A[7:4]   INX_TO_PFD_EN        0                  0x0
+ * 0x094E[11:0]  REFCLK_HYS_SEL       585                0x249
+ * 0x095E[0]     M_INTEGER            0                  0x0
+ * 0x0A02[4:0]   N_ADD_0P5            0                  0x00
+ * 0x0A03[4:0]   N_CLK_TO_OUTX_EN     7                  0x07
+ * 0x0A04[4:0]   N_PIBYP              1                  0x01
+ * 0x0A05[4:0]   N_PDNB               7                  0x07
+ * 0x0A14[3]     N0_HIGH_FREQ         0                  0x0
+ * 0x0A1A[3]     N1_HIGH_FREQ         0                  0x0
+ * 0x0A20[3]     N2_HIGH_FREQ         0                  0x0
+ * 0x0A26[3]     N3_HIGH_FREQ         0                  0x0
+ * 0x0B44[3:0]   PDIV_ENB             15                 0xF
+ * 0x0B4A[4:0]   N_CLK_DIS            8                  0x08
+ * 0x0B57[11:0]  VCO_RESET_CALCODE    270                0x10E
+ *
+ *
+ */
+
+#endif
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index d8cd83db25..0205d7de8e 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -80,6 +80,22 @@ sources = files(
     'nthw/supported/nthw_fpga_9563_055_039_0000.c',
     'nthw/supported/nthw_fpga_instances.c',
     'nthw/supported/nthw_fpga_mod_str_map.c',
+    'nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c',
+    'nthw/core/nt200a0x/nthw_fpga_nt200a0x.c',
+    'nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c',
+    'nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c',
+    'nthw/core/nthw_fpga.c',
+    'nthw/core/nthw_fpga_rst.c',
+    'nthw/core/nthw_hif.c',
+    'nthw/core/nthw_iic.c',
+    'nthw/core/nthw_mac_pcs_xxv.c',
+    'nthw/core/nthw_pcie3.c',
+    'nthw/core/nthw_sdc.c',
+    'nthw/core/nthw_si5340.c',
+    'nthw/core/nthw_spim.c',
+    'nthw/core/nthw_spis.c',
+    'nthw/core/nthw_spi_v3.c',
+    'nthw/core/nthw_tsm.c',
     'nthw/model/nthw_fpga_model.c',
     'nthw/nthw_epp.c',
     'nthw/nthw_platform.c',
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c b/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c
new file mode 100644
index 0000000000..f00e9ac053
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.c
@@ -0,0 +1,51 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nthw_clock_profiles.h"
+#include "nthw_fpga_clk9563.h"
+#include "ntnic_mod_reg.h"
+
+#define code	/* Remove this word from the array definitions */
+
+/*
+ * Clock profile for NT200A02 FPGA 9563
+ */
+#define si5340_revd_register_t type_9563_si5340_nt200a02_u23_v5
+#define si5340_revd_registers data_9563_si5340_nt200a02_u23_v5
+#include "NT200A02_U23_Si5340_adr0_v5-Registers.h"
+#ifdef __cplusplus
+static_assert(sizeof(type_9563_si5340_nt200a02_u23_v5) == sizeof(clk_profile_data_fmt2_t),
+	clk_profile_size_error_msg);
+#endif	/* __cplusplus */
+static const int n_data_9563_si5340_nt200a02_u23_v5 = SI5340_REVD_REG_CONFIG_NUM_REGS;
+static const clk_profile_data_fmt2_t *p_data_9563_si5340_nt200a02_u23_v5 =
+	(const clk_profile_data_fmt2_t *)&data_9563_si5340_nt200a02_u23_v5[0];
+
+static const int *get_n_data_9563_si5340_nt200a02_u23_v5(void)
+{
+	return &n_data_9563_si5340_nt200a02_u23_v5;
+}
+
+static const clk_profile_data_fmt2_t *get_p_data_9563_si5340_nt200a02_u23_v5(void)
+{
+	return p_data_9563_si5340_nt200a02_u23_v5;
+}
+
+static struct clk9563_ops ops = { .get_n_data_9563_si5340_nt200a02_u23_v5 =
+		get_n_data_9563_si5340_nt200a02_u23_v5,
+		.get_p_data_9563_si5340_nt200a02_u23_v5 =
+			get_p_data_9563_si5340_nt200a02_u23_v5
+};
+
+static void __attribute__((constructor(65535))) clk9563_ops_init(void)
+{
+	register_clk9563_ops(&ops);
+}
+
+#undef si5340_revd_registers
+#undef si5340_revd_register_t
+#undef SI5340_REVD_REG_CONFIG_HEADER	/* Disable the include once protection */
+
+#undef code
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.h b/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.h
new file mode 100644
index 0000000000..88d72cd334
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/clock_profiles/nthw_fpga_clk9563.h
@@ -0,0 +1,9 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef _NTHW_FPGA_CLK_9563_H_
+#define _NTHW_FPGA_CLK_9563_H_
+
+#endif	/* _NTHW_FPGA_CLK_9563_H_ */
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
new file mode 100644
index 0000000000..0f358da346
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.c
@@ -0,0 +1,107 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_fpga.h"
+#include "nthw_fpga_nt200a0x.h"
+#include "ntnic_mod_reg.h"
+
+static int nthw_fpga_nt200a0x_init(struct fpga_info_s *p_fpga_info)
+{
+	assert(p_fpga_info);
+
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	struct nthw_fpga_rst_nt200a0x rst;
+	int res = -1;
+	const struct rst_nt200a0x_ops *rst_nt200a0x_ops = get_rst_nt200a0x_ops();
+
+	if (rst_nt200a0x_ops == NULL) {
+		NT_LOG(ERR, NTHW, "RST NT200A0X NOT INCLUDED\n");
+		return -1;
+	}
+
+	/* reset common */
+	res = rst_nt200a0x_ops->nthw_fpga_rst_nt200a0x_init(p_fpga_info, &rst);
+
+	if (res) {
+		NT_LOG(ERR, NTHW, "%s: %s: loc=%u: FPGA=%04d res=%d\n", p_adapter_id_str, __func__,
+			__LINE__, p_fpga_info->n_fpga_prod_id, res);
+		return res;
+	}
+
+	bool included = true;
+	struct rst9530_ops *rst9530_ops = get_rst9530_ops();
+	struct rst9544_ops *rst9544_ops = get_rst9544_ops();
+	struct rst9563_ops *rst9563_ops = get_rst9563_ops();
+	struct rst9572_ops *rst9572_ops = get_rst9572_ops();
+
+	/* reset specific */
+	switch (p_fpga_info->n_fpga_prod_id) {
+	case 9530:
+		if (rst9530_ops != NULL)
+			res = rst9530_ops->nthw_fpga_rst9530_init(p_fpga_info, &rst);
+
+		else
+			included = false;
+
+		break;
+
+	case 9544:
+		if (rst9544_ops != NULL)
+			res = rst9544_ops->nthw_fpga_rst9544_init(p_fpga_info, &rst);
+
+		else
+			included = false;
+
+		break;
+
+	case 9563:
+		if (rst9563_ops != NULL)
+			res = rst9563_ops->nthw_fpga_rst9563_init(p_fpga_info, &rst);
+
+		else
+			included = false;
+
+		break;
+
+	case 9572:
+		if (rst9572_ops != NULL)
+			res = rst9572_ops->nthw_fpga_rst9572_init(p_fpga_info, &rst);
+
+		else
+			included = false;
+
+		break;
+
+	default:
+		NT_LOG(ERR, NTHW, "%s: Unsupported FPGA product: %04d\n", p_adapter_id_str,
+			p_fpga_info->n_fpga_prod_id);
+		res = -1;
+		break;
+	}
+
+	if (!included) {
+		NT_LOG(ERR, NTHW, "%s: NOT INCLUDED FPGA product: %04d\n", p_adapter_id_str,
+			p_fpga_info->n_fpga_prod_id);
+		res = -1;
+	}
+
+	if (res) {
+		NT_LOG(ERR, NTHW, "%s: %s: loc=%u: FPGA=%04d res=%d\n", p_adapter_id_str, __func__,
+			__LINE__, p_fpga_info->n_fpga_prod_id, res);
+		return res;
+	}
+
+	return res;
+}
+
+static struct nt200a0x_ops nt200a0x_ops = { .nthw_fpga_nt200a0x_init = nthw_fpga_nt200a0x_init };
+
+static void __attribute__((constructor(65535))) nt200a0x_ops_init(void)
+{
+	NT_LOG(INF, NTHW, "NT200A0X OPS INIT");
+	register_nt200a0x_ops(&nt200a0x_ops);
+}
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.h b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.h
new file mode 100644
index 0000000000..26efe27e0f
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/nthw_fpga_nt200a0x.h
@@ -0,0 +1,9 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+#ifndef __NTHW_FPGA_NT200A0X_H__
+#define __NTHW_FPGA_NT200A0X_H__
+
+#endif	/* __NTHW_FPGA_NT200A0X_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
new file mode 100644
index 0000000000..c113bb04b7
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.c
@@ -0,0 +1,258 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+#include "nthw_fpga.h"
+
+#include "nthw_fpga_rst9563.h"
+#include "nthw_fpga_nt200a0x.h"
+#include "nthw_fpga_rst_nt200a0x.h"
+#include "ntnic_mod_reg.h"
+
+static int nthw_fpga_rst9563_setup(nthw_fpga_t *p_fpga, struct nthw_fpga_rst_nt200a0x *const p)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	const int n_fpga_product_id = p_fpga->mn_product_id;
+	const int n_fpga_version = p_fpga->mn_fpga_version;
+	const int n_fpga_revision = p_fpga->mn_fpga_revision;
+
+	nthw_module_t *p_mod_rst;
+	nthw_register_t *p_curr_reg;
+
+	assert(p);
+	p->mn_fpga_product_id = n_fpga_product_id;
+	p->mn_fpga_version = n_fpga_version;
+	p->mn_fpga_revision = n_fpga_revision;
+
+	NT_LOG(DBG, NTHW, "%s: %s: FPGA reset setup: FPGA %04d-%02d-%02d\n", p_adapter_id_str,
+		__func__, n_fpga_product_id, n_fpga_version, n_fpga_revision);
+
+	p_mod_rst = nthw_fpga_query_module(p_fpga, MOD_RST9563, 0);
+
+	if (p_mod_rst == NULL) {
+		NT_LOG(ERR, NTHW, "%s: RST %d: no such instance\n", p_adapter_id_str, 0);
+		return -1;
+	}
+
+	p_mod_rst = nthw_fpga_query_module(p_fpga, MOD_RST9563, 0);
+
+	if (p_mod_rst == NULL) {
+		NT_LOG(ERR, NTHW, "%s: RST %d: no such instance\n", p_adapter_id_str, 0);
+		return -1;
+	}
+
+	/* RST register field pointers */
+	p_curr_reg = nthw_module_get_register(p_mod_rst, RST9563_RST);
+	p->mp_fld_rst_sys = nthw_register_get_field(p_curr_reg, RST9563_RST_SYS);
+	p->mp_fld_rst_sys_mmcm = nthw_register_get_field(p_curr_reg, RST9563_RST_SYS_MMCM);
+	p->mp_fld_rst_core_mmcm = nthw_register_get_field(p_curr_reg, RST9563_RST_CORE_MMCM);
+	p->mp_fld_rst_rpp = nthw_register_get_field(p_curr_reg, RST9563_RST_RPP);
+	p->mp_fld_rst_ddr4 = nthw_register_get_field(p_curr_reg, RST9563_RST_DDR4);
+	p->mp_fld_rst_sdc = nthw_register_get_field(p_curr_reg, RST9563_RST_SDC);
+	p->mp_fld_rst_phy = nthw_register_get_field(p_curr_reg, RST9563_RST_PHY);
+	p->mp_fld_rst_serdes_rx = NULL;	/* Field not present on 9563 */
+	p->mp_fld_rst_serdes_tx = NULL;	/* Field not present on 9563 */
+	p->mp_fld_rst_serdes_rx_datapath = NULL;/* Field not present on 9563 */
+	p->mp_fld_rst_pcs_rx = NULL;	/* Field not present on 9563 */
+	p->mp_fld_rst_mac_rx = nthw_register_get_field(p_curr_reg, RST9563_RST_MAC_RX);
+	p->mp_fld_rst_mac_tx = NULL;
+	p->mp_fld_rst_ptp = nthw_register_get_field(p_curr_reg, RST9563_RST_PTP);
+	p->mp_fld_rst_ptp = nthw_register_get_field(p_curr_reg, RST9563_RST_PTP);
+	p->mp_fld_rst_ts = nthw_register_get_field(p_curr_reg, RST9563_RST_TS);
+	p->mp_fld_rst_ptp_mmcm = nthw_register_get_field(p_curr_reg, RST9563_RST_PTP_MMCM);
+	p->mp_fld_rst_ts_mmcm = nthw_register_get_field(p_curr_reg, RST9563_RST_TS_MMCM);
+	/* referenced in separate function */
+	p->mp_fld_rst_periph = nthw_register_get_field(p_curr_reg, RST9563_RST_PERIPH);
+	p->mp_fld_rst_tsm_ref_mmcm =
+		nthw_register_query_field(p_curr_reg, RST9563_RST_TSM_REF_MMCM);
+	p->mp_fld_rst_tmc = nthw_register_query_field(p_curr_reg, RST9563_RST_TMC);
+
+	if (!p->mp_fld_rst_tsm_ref_mmcm)
+		NT_LOG(DBG, NTHW, "%s: No RST9563_RST_TSM_REF_MMCM found\n", p_adapter_id_str);
+
+	if (!p->mp_fld_rst_tmc)
+		NT_LOG(DBG, NTHW, "%s: No RST9563_RST_TMC found\n", p_adapter_id_str);
+
+	nthw_register_update(p_curr_reg);
+
+	/* CTRL register field pointers */
+	p_curr_reg = nthw_module_get_register(p_mod_rst, RST9563_CTRL);
+	p->mp_fld_ctrl_ts_clk_sel_override =
+		nthw_register_get_field(p_curr_reg, RST9563_CTRL_TS_CLKSEL_OVERRIDE);
+	/* Field not present on 9563 */
+	p->mp_fld_ctrl_ts_clk_sel = nthw_register_get_field(p_curr_reg, RST9563_CTRL_TS_CLKSEL);
+	p->mp_fld_ctrl_ts_clk_sel_ref = NULL;	/* Field not present on 9563 */
+	p->mp_fld_ctrl_ptp_mmcm_clk_sel =
+		nthw_register_get_field(p_curr_reg, RST9563_CTRL_PTP_MMCM_CLKSEL);
+	nthw_register_update(p_curr_reg);
+
+	/* STAT register field pointers */
+	p_curr_reg = nthw_module_get_register(p_mod_rst, RST9563_STAT);
+	p->mp_fld_stat_ddr4_mmcm_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_DDR4_MMCM_LOCKED);
+	p->mp_fld_stat_sys_mmcm_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_SYS_MMCM_LOCKED);
+	p->mp_fld_stat_core_mmcm_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_CORE_MMCM_LOCKED);
+	p->mp_fld_stat_ddr4_pll_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_DDR4_PLL_LOCKED);
+	p->mp_fld_stat_ptp_mmcm_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_PTP_MMCM_LOCKED);
+	p->mp_fld_stat_ts_mmcm_locked =
+		nthw_register_get_field(p_curr_reg, RST9563_STAT_TS_MMCM_LOCKED);
+	p->mp_fld_stat_tsm_ref_mmcm_locked = NULL;	/* Field not present on 9563 */
+
+	if (!p->mp_fld_stat_tsm_ref_mmcm_locked) {
+		NT_LOG(DBG, NTHW, "%s: No RST9563_STAT_TSM_REF_MMCM_LOCKED found\n",
+			p_adapter_id_str);
+	}
+
+	nthw_register_update(p_curr_reg);
+
+	/* STICKY register field pointers */
+	p_curr_reg = nthw_module_get_register(p_mod_rst, RST9563_STICKY);
+	p->mp_fld_sticky_ptp_mmcm_unlocked =
+		nthw_register_get_field(p_curr_reg, RST9563_STICKY_PTP_MMCM_UNLOCKED);
+	p->mp_fld_sticky_ts_mmcm_unlocked =
+		nthw_register_get_field(p_curr_reg, RST9563_STICKY_TS_MMCM_UNLOCKED);
+	p->mp_fld_sticky_ddr4_mmcm_unlocked =
+		nthw_register_get_field(p_curr_reg, RST9563_STICKY_DDR4_MMCM_UNLOCKED);
+	p->mp_fld_sticky_ddr4_pll_unlocked =
+		nthw_register_get_field(p_curr_reg, RST9563_STICKY_DDR4_PLL_UNLOCKED);
+	p->mp_fld_sticky_core_mmcm_unlocked =
+		nthw_register_get_field(p_curr_reg, RST9563_STICKY_CORE_MMCM_UNLOCKED);
+	p->mp_fld_sticky_pci_sys_mmcm_unlocked = NULL;	/* Field not present on 9563 */
+	p->mp_fld_sticky_tsm_ref_mmcm_unlocked = NULL;	/* Field not present on 9563 */
+
+	if (!p->mp_fld_sticky_tsm_ref_mmcm_unlocked) {
+		NT_LOG(DBG, NTHW, "%s: No RST9563_STICKY_TSM_REF_MMCM_UNLOCKED found\n",
+			p_adapter_id_str);
+	}
+
+	nthw_register_update(p_curr_reg);
+
+	/* POWER register field pointers */
+	p_curr_reg = nthw_module_get_register(p_mod_rst, RST9563_POWER);
+	p->mp_fld_power_pu_phy = nthw_register_get_field(p_curr_reg, RST9563_POWER_PU_PHY);
+	p->mp_fld_power_pu_nseb = nthw_register_get_field(p_curr_reg, RST9563_POWER_PU_NSEB);
+	nthw_register_update(p_curr_reg);
+
+	return 0;
+}
+
+static int nthw_fpga_rst9563_periph_reset(nthw_fpga_t *p_fpga)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	nthw_module_t *p_mod_rst = nthw_fpga_query_module(p_fpga, MOD_RST9563, 0);
+
+	if (p_mod_rst) {
+		nthw_register_t *p_reg_rst;
+		nthw_field_t *p_fld_rst_periph;
+		NT_LOG(DBG, NTHW, "%s: PERIPH RST\n", p_adapter_id_str);
+		p_reg_rst = nthw_module_get_register(p_mod_rst, RST9563_RST);
+		p_fld_rst_periph = nthw_register_get_field(p_reg_rst, RST9563_RST_PERIPH);
+		nthw_field_set_flush(p_fld_rst_periph);
+		nthw_field_clr_flush(p_fld_rst_periph);
+
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int nthw_fpga_rst9563_clock_synth_init(nthw_fpga_t *p_fpga,
+	const int n_si_labs_clock_synth_model,
+	const uint8_t n_si_labs_clock_synth_i2c_addr)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	const int n_fpga_product_id = p_fpga->mn_product_id;
+	int res;
+	const struct clk9563_ops *clk9563_ops = get_clk9563_ops();
+
+	if (clk9563_ops == NULL) {
+		NT_LOG(INF, ETHDEV, "CLK9563 module not included\n");
+		return -1;
+	}
+
+	if (n_si_labs_clock_synth_model == 5340) {
+		res = nthw_fpga_si5340_clock_synth_init_fmt2(p_fpga, n_si_labs_clock_synth_i2c_addr,
+				clk9563_ops->get_p_data_9563_si5340_nt200a02_u23_v5(),
+				*clk9563_ops->get_n_data_9563_si5340_nt200a02_u23_v5());
+
+	} else {
+		NT_LOG(ERR, NTHW, "%s: Fpga %d: Unsupported clock synth model (%d)\n",
+			p_adapter_id_str, n_fpga_product_id, n_si_labs_clock_synth_model);
+		res = -1;
+	}
+
+	return res;
+}
+
+static int nthw_fpga_rst9563_init(struct fpga_info_s *p_fpga_info,
+	struct nthw_fpga_rst_nt200a0x *p_rst)
+{
+	assert(p_fpga_info);
+	assert(p_rst);
+
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	int res = -1;
+	int n_si_labs_clock_synth_model;
+	uint8_t n_si_labs_clock_synth_i2c_addr;
+	nthw_fpga_t *p_fpga = NULL;
+
+	p_fpga = p_fpga_info->mp_fpga;
+	n_si_labs_clock_synth_model = p_rst->mn_si_labs_clock_synth_model;
+	n_si_labs_clock_synth_i2c_addr = p_rst->mn_si_labs_clock_synth_i2c_addr;
+
+	res = nthw_fpga_rst9563_periph_reset(p_fpga);
+
+	if (res) {
+		NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, res, __func__,
+			__LINE__);
+		return res;
+	}
+
+	res = nthw_fpga_rst9563_clock_synth_init(p_fpga, n_si_labs_clock_synth_model,
+			n_si_labs_clock_synth_i2c_addr);
+
+	if (res) {
+		NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, res, __func__,
+			__LINE__);
+		return res;
+	}
+
+	res = nthw_fpga_rst9563_setup(p_fpga, p_rst);
+
+	if (res) {
+		NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, res, __func__,
+			__LINE__);
+		return res;
+	}
+
+	const struct rst_nt200a0x_ops *rst_ops = get_rst_nt200a0x_ops();
+	res = rst_ops != NULL ? rst_ops->nthw_fpga_rst_nt200a0x_reset(p_fpga, p_rst) : -1;
+
+	if (res) {
+		NT_LOG(DBG, NTHW, "%s: ERROR: res=%d [%s:%u]\n", p_adapter_id_str, res, __func__,
+			__LINE__);
+		return res;
+	}
+
+	return res;
+}
+
+static struct rst9563_ops rst9563_ops = { .nthw_fpga_rst9563_init = nthw_fpga_rst9563_init };
+
+static void __attribute__((constructor(65535))) rst9563_ops_init(void)
+{
+	NT_LOG(INF, NTHW, "RST9563 OPS INIT");
+	register_rst9563_ops(&rst9563_ops);
+}
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.h b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.h
new file mode 100644
index 0000000000..e61cd32954
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst9563.h
@@ -0,0 +1,9 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_FPGA_RST9563_H__
+#define __NTHW_FPGA_RST9563_H__
+
+#endif	/* __NTHW_FPGA_RST9563_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
new file mode 100644
index 0000000000..d323d9a93f
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.c
@@ -0,0 +1,729 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+#include "nthw_fpga.h"
+
+#include "nthw_fpga_rst_nt200a0x.h"
+#include "nthw_fpga_nt200a0x.h"
+#include "ntnic_mod_reg.h"
+
+static const uint8_t si5338_u23_i2c_addr_7bit = 0x70;
+static const uint8_t si5340_u23_i2c_addr_7bit = 0x74;
+
+/*
+ * Wait until DDR4 PLL LOCKED
+ */
+static int nthw_fpga_rst_nt200a0x_wait_ddr4_pll_locked(nthw_fpga_t *p_fpga,
+	const struct nthw_fpga_rst_nt200a0x *p)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	uint32_t locked;
+	uint32_t retrycount = 5;
+	uint32_t timeout = 50000;	/* initial timeout must be set to 5 sec. */
+	/* 14: wait until DDR4 PLL LOCKED */
+	NT_LOG(DBG, NTHW, "%s: Waiting for DDR4 PLL to lock\n", p_adapter_id_str);
+
+	/*
+	 * The following retry count gives a total timeout of 1 * 5 + 5 * 8 = 45sec
+	 * It has been observed that at least 21sec can be necessary
+	 */
+	while (true) {
+		int locked =
+			nthw_field_wait_set_any32(p->mp_fld_stat_ddr4_pll_locked, timeout, 100);
+
+		if (locked == 0) {
+			break;
+
+		} else {
+			NT_LOG(DBG, NTHW, "%s: Waiting for DDR4 PLL to lock - timeout\n",
+				p_adapter_id_str);
+
+			if (retrycount <= 0) {
+				NT_LOG(ERR, NTHW, "%s: Waiting for DDR4 PLL to lock failed (%d)\n",
+					p_adapter_id_str, locked);
+				break;
+			}
+
+			nthw_field_set_flush(p->mp_fld_rst_ddr4);	/* Reset DDR PLL */
+			nthw_field_clr_flush(p->mp_fld_rst_ddr4);	/* Reset DDR PLL */
+			retrycount--;
+			timeout = 80000;/* Increase timeout for second attempt to 8 sec. */
+		}
+	}
+
+	NT_LOG(DBG, NTHW, "%s: Waiting for DDR4 MMCM to lock\n", p_adapter_id_str);
+	locked = nthw_field_wait_set_any32(p->mp_fld_stat_ddr4_mmcm_locked, -1, -1);
+
+	if (locked != 0) {
+		NT_LOG(ERR, NTHW, "%s: Waiting for DDR4 MMCM to lock failed (%d)\n",
+			p_adapter_id_str, locked);
+		return -1;
+	}
+
+	if (true && p->mp_fld_stat_tsm_ref_mmcm_locked) {
+		NT_LOG(DBG, NTHW, "%s: Waiting for TSM REF MMCM to lock\n", p_adapter_id_str);
+		locked = nthw_field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, -1, -1);
+
+		if (locked != 0) {
+			NT_LOG(ERR, NTHW, "%s: Waiting for TSM REF MMCM to lock failed (%d)\n",
+				p_adapter_id_str, locked);
+			return -1;
+		}
+	}
+
+	/* 10: Clear all MMCM/PLL lock sticky bits before testing them */
+	NT_LOG(DBG, NTHW, "%s: Clear sticky MMCM unlock bits\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_sticky_ptp_mmcm_unlocked);
+	/* Clear all sticky bits */
+	nthw_field_set_flush(p->mp_fld_sticky_ptp_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ts_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ddr4_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ddr4_pll_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_core_mmcm_unlocked);
+
+	if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked)
+		nthw_field_set_flush(p->mp_fld_sticky_tsm_ref_mmcm_unlocked);
+
+	if (p->mp_fld_sticky_pci_sys_mmcm_unlocked)
+		nthw_field_set_flush(p->mp_fld_sticky_pci_sys_mmcm_unlocked);
+
+	/* 11: Ensure sticky bits are not unlocked except PTP MMCM and TS MMCM */
+	if (nthw_field_get_updated(p->mp_fld_sticky_ddr4_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_ddr4_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+	}
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_ddr4_pll_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_ddr4_pll_unlocked() returned true\n",
+			p_adapter_id_str);
+	}
+
+	return 0;
+}
+
+/*
+ * Wait for SDRAM controller has been calibrated - On some adapters we have seen
+ * calibration time of 2.3 seconds
+ */
+static int nthw_fpga_rst_nt200a0x_wait_sdc_calibrated(nthw_fpga_t *p_fpga,
+	const struct nthw_fpga_rst_nt200a0x *p)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_sdc_t *p_nthw_sdc = NULL;
+	const int n_retry_cnt_max = 5;
+	int n_retry_cnt;
+	int res;
+
+	res = nthw_sdc_init(NULL, p_fpga, 0);	/* probe for module */
+
+	if (res == 0) {
+		p_nthw_sdc = nthw_sdc_new();
+
+		if (p_nthw_sdc) {
+			res = nthw_sdc_init(p_nthw_sdc, p_fpga, 0);
+
+			if (res) {
+				NT_LOG(ERR, NTHW, "%s: SDC init failed: res=%d [%s:%d]\n",
+					p_adapter_id_str, res, __func__, __LINE__);
+				nthw_sdc_delete(p_nthw_sdc);
+				p_nthw_sdc = NULL;
+				return -1;
+			}
+
+		} else {
+			nthw_sdc_delete(p_nthw_sdc);
+			p_nthw_sdc = NULL;
+		}
+
+	} else {
+		NT_LOG(DBG, NTHW, "%s: No SDC found\n", p_adapter_id_str);
+	}
+
+	n_retry_cnt = 0;
+	res = -1;
+
+	while ((res != 0) && (n_retry_cnt <= n_retry_cnt_max)) {
+		/* wait until DDR4 PLL LOCKED */
+		res = nthw_fpga_rst_nt200a0x_wait_ddr4_pll_locked(p_fpga, p);
+
+		if (res == 0) {
+			if (p_nthw_sdc) {
+				/*
+				 * Wait for SDRAM controller has been calibrated
+				 * On some adapters we have seen calibration time of 2.3 seconds
+				 */
+				NT_LOG(DBG, NTHW, "%s: Waiting for SDRAM to calibrate\n",
+					p_adapter_id_str);
+				res = nthw_sdc_wait_states(p_nthw_sdc, 10000, 1000);
+				{
+					uint64_t n_result_mask;
+					int n_state_code =
+						nthw_sdc_get_states(p_nthw_sdc, &n_result_mask);
+					(void)n_state_code;
+					NT_LOG(DBG, NTHW,
+						"%s: SDRAM state=0x%08lX state_code=%d retry=%d code=%d\n",
+						p_adapter_id_str, n_result_mask, n_state_code,
+						n_retry_cnt, res);
+				}
+
+				if (res == 0)
+					break;
+			}
+
+			if (n_retry_cnt >= n_retry_cnt_max) {
+				uint64_t n_result_mask;
+				int n_state_code = nthw_sdc_get_states(p_nthw_sdc, &n_result_mask);
+				(void)n_state_code;
+
+				NT_LOG(DBG, NTHW,
+					"%s: SDRAM state=0x%08lX state_code=%d retry=%d code=%d\n",
+					p_adapter_id_str, n_result_mask, n_state_code, n_retry_cnt,
+					res);
+
+				if (res != 0) {
+					NT_LOG(ERR, NTHW,
+						"%s: Timeout waiting for SDRAM controller calibration\n",
+						p_adapter_id_str);
+				}
+			}
+		}
+
+		/*
+		 * SDRAM controller is not calibrated with DDR4 ram blocks:
+		 * reset DDR and perform calibration retry
+		 */
+		nthw_field_set_flush(p->mp_fld_rst_ddr4);	/* Reset DDR PLL */
+		nt_os_wait_usec(100);
+		nthw_field_clr_flush(p->mp_fld_rst_ddr4);
+
+		n_retry_cnt++;
+	}
+
+	nthw_sdc_delete(p_nthw_sdc);
+
+	return res;
+}
+
+static int nthw_fpga_rst_nt200a0x_reset(nthw_fpga_t *p_fpga,
+	const struct nthw_fpga_rst_nt200a0x *p)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	const fpga_info_t *const p_fpga_info = p_fpga->p_fpga_info;
+
+	const int n_fpga_product_id = p->mn_fpga_product_id;
+	const int n_fpga_version = p->mn_fpga_version;
+	const int n_fpga_revision = p->mn_fpga_revision;
+	const int n_nthw_adapter_id = p_fpga_info->n_nthw_adapter_id;
+	const bool b_is_nt200a01 = (n_nthw_adapter_id == NT_HW_ADAPTER_ID_NT200A01);
+	const int n_hw_id = p_fpga_info->nthw_hw_info.hw_id;
+	const uint8_t index = 0;
+	int locked;
+	int res = -1;
+
+	NT_LOG(DBG, NTHW, "%s: %s: FPGA reset sequence: FPGA %04d-%02d-%02d @ HWId%d\n",
+		p_adapter_id_str, __func__, n_fpga_product_id, n_fpga_version, n_fpga_revision,
+		n_hw_id);
+	assert(n_fpga_product_id == p_fpga->mn_product_id);
+
+	/*
+	 * Reset all domains / modules except peripherals
+	 * Set default reset values to ensure that all modules are reset correctly
+	 * no matter if nic has been powercycled or ntservice has been reloaded
+	 */
+
+	/*
+	 * reset to defaults
+	 * 1: Reset all domains
+	 */
+	NT_LOG(DBG, NTHW, "%s: RST defaults\n", p_adapter_id_str);
+
+	nthw_field_update_register(p->mp_fld_rst_sys);
+	nthw_field_set_flush(p->mp_fld_rst_sys);
+
+	if (p->mp_fld_rst_tmc)
+		nthw_field_set_flush(p->mp_fld_rst_tmc);
+
+	nthw_field_set_flush(p->mp_fld_rst_rpp);
+	nthw_field_set_flush(p->mp_fld_rst_ddr4);	/* 0x07 3 banks */
+	nthw_field_set_flush(p->mp_fld_rst_sdc);
+
+	/* Reset port 0 and 1 in the following registers: */
+	nthw_field_set_flush(p->mp_fld_rst_phy);/* 0x03 2 ports */
+
+	if (p->mp_fld_rst_mac_rx)
+		nthw_field_set_flush(p->mp_fld_rst_mac_rx);	/* 0x03 2 ports */
+
+	if (p->mp_fld_rst_mac_tx)
+		nthw_field_set_flush(p->mp_fld_rst_mac_tx);	/* 0x03 2 ports */
+
+	if (p->mp_fld_rst_pcs_rx)
+		nthw_field_set_flush(p->mp_fld_rst_pcs_rx);	/* 0x03 2 ports */
+
+	if (p->mp_fld_rst_serdes_rx)
+		nthw_field_set_flush(p->mp_fld_rst_serdes_rx);	/* 0x03 2 ports */
+
+	if (p->mp_fld_rst_serdes_rx_datapath) {
+		nthw_field_set_flush(p->mp_fld_rst_serdes_rx_datapath);
+		nthw_field_clr_flush(p->mp_fld_rst_serdes_rx);
+	}
+
+	if (p->mp_fld_rst_serdes_tx)
+		nthw_field_set_flush(p->mp_fld_rst_serdes_tx);
+
+	nthw_field_set_flush(p->mp_fld_rst_ptp);
+	nthw_field_set_flush(p->mp_fld_rst_ts);
+	nthw_field_set_flush(p->mp_fld_rst_sys_mmcm);
+	nthw_field_set_flush(p->mp_fld_rst_core_mmcm);
+	nthw_field_set_flush(p->mp_fld_rst_ptp_mmcm);
+	nthw_field_set_flush(p->mp_fld_rst_ts_mmcm);
+
+	if (true && p->mp_fld_rst_tsm_ref_mmcm)
+		nthw_field_set_flush(p->mp_fld_rst_tsm_ref_mmcm);
+
+	/* Write all changes to register */
+	nthw_field_flush_register(p->mp_fld_rst_sys);
+
+	if (b_is_nt200a01 && n_hw_id == 2) {	/* Not relevant to NT200A02 */
+		if (p->mp_fld_rst_tsm_ref_mmcm) {
+			nthw_field_update_register(p->mp_fld_rst_tsm_ref_mmcm);
+			nthw_field_set_flush(p->mp_fld_rst_tsm_ref_mmcm);
+		}
+	}
+
+	/*
+	 * 2: Force use of 50 MHz reference clock for timesync;
+	 * NOTE: From 9508-05-18 this is a 20 MHz clock
+	 */
+	NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL OVERRIDE\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_ctrl_ts_clk_sel_override);
+	nthw_field_set_flush(p->mp_fld_ctrl_ts_clk_sel_override);
+
+	NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_ctrl_ts_clk_sel);
+	nthw_field_set_flush(p->mp_fld_ctrl_ts_clk_sel);
+
+	if (b_is_nt200a01 && n_hw_id == 2) {	/* Not relevant to NT200A02 */
+		NT_LOG(DBG, NTHW, "%s: Selecting 20MHz TS CLK SEL REF\n", p_adapter_id_str);
+
+		if (p->mp_fld_ctrl_ts_clk_sel_ref) {
+			nthw_field_update_register(p->mp_fld_ctrl_ts_clk_sel_ref);
+			nthw_field_clr_flush(p->mp_fld_ctrl_ts_clk_sel_ref);
+		}
+	}
+
+	/* 4: De-assert sys reset, CORE and SYS MMCM resets */
+	NT_LOG(DBG, NTHW, "%s: De-asserting SYS, CORE and SYS MMCM resets\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_rst_sys);
+	nthw_field_clr_flush(p->mp_fld_rst_sys);
+	nthw_field_clr_flush(p->mp_fld_rst_sys_mmcm);
+	nthw_field_clr_flush(p->mp_fld_rst_core_mmcm);
+
+	/* 5: wait until CORE MMCM and SYS MMCM are LOCKED */
+	NT_LOG(DBG, NTHW, "%s: Waiting for SYS MMCM to lock\n", p_adapter_id_str);
+	locked = nthw_field_wait_set_any32(p->mp_fld_stat_sys_mmcm_locked, -1, -1);
+
+	if (locked != 0) {
+		NT_LOG(ERR, NTHW, "%s: Waiting for SYS MMCM to lock failed (%d)\n",
+			p_adapter_id_str, locked);
+	}
+
+	NT_LOG(DBG, NTHW, "%s: Waiting for CORE MMCM to lock\n", p_adapter_id_str);
+	locked = nthw_field_wait_set_any32(p->mp_fld_stat_core_mmcm_locked, -1, -1);
+
+	if (locked != 0) {
+		NT_LOG(ERR, NTHW, "%s: Waiting for CORE MMCM to lock failed (%d)\n",
+			p_adapter_id_str, locked);
+	}
+
+	/*
+	 * RAC RAB bus "flip/flip" reset second stage - new impl (ref RMT#37020)
+	 * RAC/RAB init - SYS/CORE MMCM is locked - pull the remaining RAB busses out of reset
+	 */
+	{
+		nthw_rac_t *p_nthw_rac = p_fpga_info->mp_nthw_rac;
+		NT_LOG(DBG, NTHW, "%s: De-asserting remaining RAB busses\n", p_adapter_id_str);
+		nthw_rac_rab_init(p_nthw_rac, 0);
+	}
+
+	if (true && p->mp_fld_rst_tsm_ref_mmcm) {
+		NT_LOG(DBG, NTHW, "%s: De-asserting TSM REF MMCM\n", p_adapter_id_str);
+		nthw_field_clr_flush(p->mp_fld_rst_tsm_ref_mmcm);
+
+		if (p->mp_fld_stat_tsm_ref_mmcm_locked) {
+			NT_LOG(DBG, NTHW, "%s: Waiting for TSM REF MMCM to lock\n",
+				p_adapter_id_str);
+			locked = nthw_field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, -1,
+					-1);
+
+			if (locked != 0) {
+				NT_LOG(ERR, NTHW,
+					"%s: Waiting for TSM REF MMCM to lock failed (%d)\n",
+					p_adapter_id_str, locked);
+			}
+		}
+	}
+
+	/*
+	 * 5.2: Having ensured CORE MMCM and SYS MMCM are LOCKED,
+	 * we need to select the alternative 20 MHz reference clock,
+	 * the external TSM reference clock
+	 * on NT200A01 - build 2 HW only (see SSF00024 p.32)
+	 */
+	if (b_is_nt200a01 && n_hw_id == 2) {	/* Not relevant to NT200A02 */
+		NT_LOG(DBG, NTHW, "%s: Setting TS CLK SEL REF\n", p_adapter_id_str);
+
+		if (p->mp_fld_ctrl_ts_clk_sel_ref)
+			nthw_field_set_flush(p->mp_fld_ctrl_ts_clk_sel_ref);
+
+		if (p->mp_fld_rst_tsm_ref_mmcm) {
+			NT_LOG(DBG, NTHW, "%s: De-asserting TSM REF MMCM\n", p_adapter_id_str);
+			nthw_field_clr_flush(p->mp_fld_rst_tsm_ref_mmcm);
+		}
+
+		NT_LOG(DBG, NTHW, "%s: Waiting for TSM REF MMCM to lock\n", p_adapter_id_str);
+
+		if (p->mp_fld_stat_tsm_ref_mmcm_locked) {
+			locked = nthw_field_wait_set_any32(p->mp_fld_stat_tsm_ref_mmcm_locked, -1,
+					-1);
+
+			if (locked != 0) {
+				NT_LOG(ERR, NTHW,
+					"%s: Waiting for TSM REF MMCM to lock failed (%d)\n",
+					p_adapter_id_str, locked);
+			}
+		}
+	}
+
+	NT_LOG(DBG, NTHW, "%s: De-asserting all PHY resets\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_rst_phy);
+	nthw_field_clr_flush(p->mp_fld_rst_phy);
+
+	/* MAC_PCS_XXV 10G/25G: 9530 / 9544 */
+	if (n_fpga_product_id == 9530 || n_fpga_product_id == 9544) {
+		{
+			/* Based on nt200e3_2_ptp.cpp My25GbPhy::resetRx */
+			nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv0 = nthw_mac_pcs_xxv_new();
+			assert(p_nthw_mac_pcs_xxv0);
+			nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv0, p_fpga, 0, 1, false);
+
+			nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, true, index);
+			nt_os_wait_usec(1000);
+
+			nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, false, index);
+			nt_os_wait_usec(1000);
+
+			nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv0);
+		}
+
+		{
+			/* Based on nt200e3_2_ptp.cpp My25GbPhy::resetRx */
+			nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv1 = nthw_mac_pcs_xxv_new();
+			assert(p_nthw_mac_pcs_xxv1);
+			nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv1, p_fpga, 1, 1, false);
+
+			nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, true, index);
+			nt_os_wait_usec(1000);
+
+			nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, false, index);
+			nt_os_wait_usec(1000);
+
+			nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv1);
+		}
+		nt_os_wait_usec(3000);
+	}
+
+	/* MAC_PCS_XXV 8x10G: 9572 */
+	if (n_fpga_product_id == 9572) {
+		{
+			nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv0 = nthw_mac_pcs_xxv_new();
+			assert(p_nthw_mac_pcs_xxv0);
+			nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv0, p_fpga, 0, 4, true);
+
+			for (int i = 0; i < 4; i++) {
+				nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, true, i);
+				nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p_nthw_mac_pcs_xxv0, true, i);
+				nt_os_wait_usec(1000);
+
+				nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv0, false, i);
+				nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p_nthw_mac_pcs_xxv0, false, i);
+				nt_os_wait_usec(1000);
+			}
+
+			nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv0);
+		}
+
+		{
+			nthw_mac_pcs_xxv_t *p_nthw_mac_pcs_xxv1 = nthw_mac_pcs_xxv_new();
+			assert(p_nthw_mac_pcs_xxv1);
+			nthw_mac_pcs_xxv_init(p_nthw_mac_pcs_xxv1, p_fpga, 1, 4, true);
+
+			for (int i = 0; i < 4; i++) {
+				nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, true, i);
+				nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p_nthw_mac_pcs_xxv1, true, i);
+				nt_os_wait_usec(1000);
+
+				nthw_mac_pcs_xxv_reset_rx_gt_data(p_nthw_mac_pcs_xxv1, false, i);
+				nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(p_nthw_mac_pcs_xxv1, false, i);
+				nt_os_wait_usec(1000);
+			}
+
+			nthw_mac_pcs_xxv_delete(p_nthw_mac_pcs_xxv1);
+		}
+		nt_os_wait_usec(3000);
+	}
+
+	/*
+	 * 8: De-assert reset for remaining domains/modules resets except
+	 * TS, PTP, PTP_MMCM and TS_MMCM
+	 */
+	NT_LOG(DBG, NTHW, "%s: De-asserting TMC RST\n", p_adapter_id_str);
+
+	if (p->mp_fld_rst_tmc) {
+		nthw_field_update_register(p->mp_fld_rst_tmc);
+		nthw_field_clr_flush(p->mp_fld_rst_tmc);
+	}
+
+	NT_LOG(DBG, NTHW, "%s: De-asserting RPP RST\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_rst_rpp);
+	nthw_field_clr_flush(p->mp_fld_rst_rpp);
+
+	NT_LOG(DBG, NTHW, "%s: De-asserting DDR4 RST\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_rst_ddr4);
+	nthw_field_clr_flush(p->mp_fld_rst_ddr4);
+
+	NT_LOG(DBG, NTHW, "%s: De-asserting SDC RST\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_rst_sdc);
+	nthw_field_clr_flush(p->mp_fld_rst_sdc);
+
+	/* NOTE: 9522 implements PHY10G_QPLL reset and lock at this stage in mac_rx_rst() */
+	NT_LOG(DBG, NTHW, "%s: De-asserting MAC RX RST\n", p_adapter_id_str);
+
+	if (p->mp_fld_rst_mac_rx) {
+		nthw_field_update_register(p->mp_fld_rst_mac_rx);
+		nthw_field_clr_flush(p->mp_fld_rst_mac_rx);
+	}
+
+	/* await until DDR4 PLL LOCKED and SDRAM controller has been calibrated */
+	res = nthw_fpga_rst_nt200a0x_wait_sdc_calibrated(p_fpga, p);
+
+	if (res) {
+		NT_LOG(ERR, NTHW,
+			"%s: nthw_fpga_rst_nt200a0x_wait_sdc_calibrated() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_core_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_core_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (p->mp_fld_sticky_pci_sys_mmcm_unlocked &&
+		nthw_field_get_updated(p->mp_fld_sticky_pci_sys_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_pci_sys_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (b_is_nt200a01 && n_hw_id == 2) {	/* Not relevant to NT200A02 */
+		if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked &&
+			nthw_field_get_updated(p->mp_fld_sticky_tsm_ref_mmcm_unlocked)) {
+			NT_LOG(ERR, NTHW, "%s: get_sticky_tsm_ref_mmcm_unlocked returned true\n",
+				p_adapter_id_str);
+			return -1;
+		}
+	}
+
+	/*
+	 * Timesync/PTP reset sequence
+	 * De-assert TS_MMCM reset
+	 */
+	NT_LOG(DBG, NTHW, "%s: De-asserting TS MMCM RST\n", p_adapter_id_str);
+	nthw_field_clr_flush(p->mp_fld_rst_ts_mmcm);
+
+	/* Wait until TS_MMCM LOCKED (NT_RAB0_REG_P9508_RST9508_STAT_TS_MMCM_LOCKED=1); */
+	NT_LOG(DBG, NTHW, "%s: Waiting for TS MMCM to lock\n", p_adapter_id_str);
+	locked = nthw_field_wait_set_any32(p->mp_fld_stat_ts_mmcm_locked, -1, -1);
+
+	if (locked != 0) {
+		NT_LOG(ERR, NTHW, "%s: Waiting for TS MMCM to lock failed (%d)\n",
+			p_adapter_id_str, locked);
+	}
+
+	NT_LOG(DBG, NTHW, "%s: Calling clear_sticky_mmcm_unlock_bits()\n", p_adapter_id_str);
+	nthw_field_update_register(p->mp_fld_sticky_ptp_mmcm_unlocked);
+	/* Clear all sticky bits */
+	nthw_field_set_flush(p->mp_fld_sticky_ptp_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ts_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ddr4_mmcm_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_ddr4_pll_unlocked);
+	nthw_field_set_flush(p->mp_fld_sticky_core_mmcm_unlocked);
+
+	if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked)
+		nthw_field_set_flush(p->mp_fld_sticky_tsm_ref_mmcm_unlocked);
+
+	if (p->mp_fld_sticky_pci_sys_mmcm_unlocked)
+		nthw_field_set_flush(p->mp_fld_sticky_pci_sys_mmcm_unlocked);
+
+	/* De-assert TS reset bit */
+	NT_LOG(DBG, NTHW, "%s: De-asserting TS RST\n", p_adapter_id_str);
+	nthw_field_clr_flush(p->mp_fld_rst_ts);
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_ts_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_ts_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_ddr4_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_ddr4_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_ddr4_pll_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_ddr4_pll_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (nthw_field_get_updated(p->mp_fld_sticky_core_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_core_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (p->mp_fld_sticky_pci_sys_mmcm_unlocked &&
+		nthw_field_get_updated(p->mp_fld_sticky_pci_sys_mmcm_unlocked)) {
+		NT_LOG(ERR, NTHW, "%s: get_sticky_pci_sys_mmcm_unlocked() returned true\n",
+			p_adapter_id_str);
+		return -1;
+	}
+
+	if (b_is_nt200a01 && n_hw_id == 2) {	/* Not relevant to NT200A02 */
+		if (p->mp_fld_sticky_tsm_ref_mmcm_unlocked &&
+			nthw_field_get_updated(p->mp_fld_sticky_tsm_ref_mmcm_unlocked)) {
+			NT_LOG(ERR, NTHW, "%s: get_sticky_tsm_ref_mmcm_unlocked() returned true\n",
+				p_adapter_id_str);
+			return -1;
+		}
+	}
+
+	if (false) {
+		/* Deassert PTP_MMCM */
+		NT_LOG(DBG, NTHW, "%s: De-asserting PTP MMCM RST\n", p_adapter_id_str);
+		nthw_field_clr_flush(p->mp_fld_rst_ptp_mmcm);
+
+		if ((b_is_nt200a01 && n_fpga_version >= 9) || !b_is_nt200a01) {
+			/* Wait until PTP_MMCM LOCKED */
+			NT_LOG(DBG, NTHW, "%s: Waiting for PTP MMCM to lock\n", p_adapter_id_str);
+			locked = nthw_field_wait_set_any32(p->mp_fld_stat_ptp_mmcm_locked, -1, -1);
+
+			if (locked != 0) {
+				NT_LOG(ERR, NTHW, "%s: Waiting for PTP MMCM to lock failed (%d)\n",
+					p_adapter_id_str, locked);
+			}
+		}
+
+		/* Switch PTP MMCM sel to use ptp clk */
+		NT_LOG(DBG, NTHW, "%s: Setting PTP MMCM CLK SEL\n", p_adapter_id_str);
+		nthw_field_set_flush(p->mp_fld_ctrl_ptp_mmcm_clk_sel);
+
+		/* Wait until TS_MMCM LOCKED (NT_RAB0_REG_P9508_RST9508_STAT_TS_MMCM_LOCKED=1); */
+		NT_LOG(DBG, NTHW, "%s: Waiting for TS MMCM to re-lock\n", p_adapter_id_str);
+		locked = nthw_field_wait_set_any32(p->mp_fld_stat_ts_mmcm_locked, -1, -1);
+
+		if (locked != 0) {
+			NT_LOG(ERR, NTHW, "%s: Waiting for TS MMCM to re-lock failed (%d)\n",
+				p_adapter_id_str, locked);
+		}
+	}
+
+	NT_LOG(DBG, NTHW, "%s: De-asserting PTP RST\n", p_adapter_id_str);
+	nthw_field_clr_flush(p->mp_fld_rst_ptp);
+
+	/* POWER staging introduced in 9508-05-09 and always for 9512 */
+	if (n_fpga_product_id == 9508 && n_fpga_version <= 5 && n_fpga_revision <= 8) {
+		NT_LOG(DBG, NTHW, "%s: No power staging\n", p_adapter_id_str);
+
+	} else {
+		NT_LOG(DBG, NTHW, "%s: Staging power\n", p_adapter_id_str);
+		nthw_field_set_flush(p->mp_fld_power_pu_phy);	/* PHY power up */
+		nthw_field_clr_flush(p->mp_fld_power_pu_nseb);	/* NSEB power down */
+	}
+
+	NT_LOG(DBG, NTHW, "%s: %s: END\n", p_adapter_id_str, __func__);
+
+	return 0;
+}
+
+static int nthw_fpga_rst_nt200a0x_init(struct fpga_info_s *p_fpga_info,
+	struct nthw_fpga_rst_nt200a0x *p_rst)
+{
+	assert(p_fpga_info);
+
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	int res = -1;
+	int n_si_labs_clock_synth_model = -1;
+	uint8_t n_si_labs_clock_synth_i2c_addr = 0;
+	nthw_fpga_t *p_fpga = NULL;
+
+	p_fpga = p_fpga_info->mp_fpga;
+
+	NT_LOG(DBG, NTHW, "%s: %s: RAB init/reset\n", p_adapter_id_str, __func__);
+	nthw_rac_rab_reset(p_fpga_info->mp_nthw_rac);
+	nthw_rac_rab_setup(p_fpga_info->mp_nthw_rac);
+
+	res = nthw_fpga_avr_probe(p_fpga, 0);
+
+	res = nthw_fpga_iic_scan(p_fpga, 0, 0);
+	res = nthw_fpga_iic_scan(p_fpga, 2, 3);
+
+	/*
+	 * Detect clock synth model
+	 * check for NT200A02/NT200A01 HW-build2 - most commonly seen
+	 */
+	n_si_labs_clock_synth_i2c_addr = si5340_u23_i2c_addr_7bit;
+	n_si_labs_clock_synth_model =
+		nthw_fpga_silabs_detect(p_fpga, 0, n_si_labs_clock_synth_i2c_addr, 1);
+
+	if (n_si_labs_clock_synth_model == -1) {
+		/* check for old NT200A01 HW-build1 */
+		n_si_labs_clock_synth_i2c_addr = si5338_u23_i2c_addr_7bit;
+		n_si_labs_clock_synth_model =
+			nthw_fpga_silabs_detect(p_fpga, 0, n_si_labs_clock_synth_i2c_addr, 255);
+
+		if (n_si_labs_clock_synth_model == -1) {
+			NT_LOG(ERR, NTHW, "%s: Failed to detect clock synth model (%d)\n",
+				p_adapter_id_str, n_si_labs_clock_synth_model);
+			return -1;
+		}
+	}
+
+	p_rst->mn_si_labs_clock_synth_model = n_si_labs_clock_synth_model;
+	p_rst->mn_si_labs_clock_synth_i2c_addr = n_si_labs_clock_synth_i2c_addr;
+	p_rst->mn_hw_id = p_fpga_info->nthw_hw_info.hw_id;
+	NT_LOG(DBG, NTHW, "%s: %s: Si%04d @ 0x%02x\n", p_adapter_id_str, __func__,
+		p_rst->mn_si_labs_clock_synth_model, p_rst->mn_si_labs_clock_synth_i2c_addr);
+
+	return res;
+}
+
+static struct rst_nt200a0x_ops rst_nt200a0x_ops = { .nthw_fpga_rst_nt200a0x_init =
+		nthw_fpga_rst_nt200a0x_init,
+		.nthw_fpga_rst_nt200a0x_reset =
+			nthw_fpga_rst_nt200a0x_reset
+};
+
+static void __attribute__((constructor(65535))) rst_nt200a0x_ops_init(void)
+{
+	NT_LOG(INF, NTHW, "RST NT200A0X OPS INIT");
+	register_rst_nt200a0x_ops(&rst_nt200a0x_ops);
+}
diff --git a/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.h b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.h
new file mode 100644
index 0000000000..af508bd2bd
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nt200a0x/reset/nthw_fpga_rst_nt200a0x.h
@@ -0,0 +1,9 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_FPGA_RST_NT200A0X_H__
+#define __NTHW_FPGA_RST_NT200A0X_H__
+
+#endif	/* __NTHW_FPGA_RST_NT200A0X_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.c b/drivers/net/ntnic/nthw/core/nthw_fpga.c
new file mode 100644
index 0000000000..bc03ff97d2
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_fpga.c
@@ -0,0 +1,888 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_fpga.h"
+
+#include "nthw_fpga_instances.h"
+#include "nthw_fpga_mod_str_map.h"
+
+#include "nthw_spi_v3.h"
+
+#include <arpa/inet.h>
+
+int nthw_fpga_get_param_info(struct fpga_info_s *p_fpga_info, nthw_fpga_t *p_fpga)
+{
+	mcu_info_t *p_mcu_info = &p_fpga_info->mcu_info;
+
+	const int n_nims = nthw_fpga_get_product_param(p_fpga, NT_NIMS, -1);
+	const int n_phy_ports = nthw_fpga_get_product_param(p_fpga, NT_PHY_PORTS, -1);
+	const int n_phy_quads = nthw_fpga_get_product_param(p_fpga, NT_PHY_QUADS, -1);
+	const int n_rx_ports = nthw_fpga_get_product_param(p_fpga, NT_RX_PORTS, -1);
+	const int n_tx_ports = nthw_fpga_get_product_param(p_fpga, NT_TX_PORTS, -1);
+	const int n_vf_offset = nthw_fpga_get_product_param(p_fpga, NT_HIF_VF_OFFSET, 4);
+
+	p_fpga_info->n_nims = n_nims;
+	p_fpga_info->n_phy_ports = n_phy_ports;
+	p_fpga_info->n_phy_quads = n_phy_quads;
+	p_fpga_info->n_rx_ports = n_rx_ports;
+	p_fpga_info->n_tx_ports = n_tx_ports;
+	p_fpga_info->n_vf_offset = n_vf_offset;
+	p_fpga_info->profile = FPGA_INFO_PROFILE_UNKNOWN;
+
+	/* Check for MCU */
+	if (nthw_fpga_get_product_param(p_fpga, NT_MCU_PRESENT, 0) != 0) {
+		p_mcu_info->mb_has_mcu = true;
+		/* Check MCU Type */
+		p_mcu_info->mn_mcu_type = nthw_fpga_get_product_param(p_fpga, NT_MCU_TYPE, -1);
+		/* MCU DRAM size */
+		p_mcu_info->mn_mcu_dram_size =
+			nthw_fpga_get_product_param(p_fpga, NT_MCU_DRAM_SIZE, -1);
+
+	} else {
+		p_mcu_info->mb_has_mcu = false;
+		p_mcu_info->mn_mcu_type = -1;
+		p_mcu_info->mn_mcu_dram_size = -1;
+	}
+
+	/* Check for VSWITCH FPGA */
+	if (nthw_fpga_get_product_param(p_fpga, NT_NFV_OVS_PRODUCT, 0) != 0) {
+		p_fpga_info->profile = FPGA_INFO_PROFILE_VSWITCH;
+
+	} else if (nthw_fpga_get_product_param(p_fpga, NT_IOA_PRESENT, 0) != 0) {
+		/* Check for VSWITCH FPGA - legacy */
+		p_fpga_info->profile = FPGA_INFO_PROFILE_VSWITCH;
+
+	} else if (nthw_fpga_get_product_param(p_fpga, NT_QM_PRESENT, 0) != 0) {
+		p_fpga_info->profile = FPGA_INFO_PROFILE_CAPTURE;
+
+	} else {
+		p_fpga_info->profile = FPGA_INFO_PROFILE_INLINE;
+	}
+
+	return 0;
+}
+
+int nthw_fpga_iic_scan(nthw_fpga_t *p_fpga, const int n_instance_no_begin,
+	const int n_instance_no_end)
+{
+	int i;
+
+	assert(n_instance_no_begin <= n_instance_no_end);
+
+	for (i = n_instance_no_begin; i <= n_instance_no_end; i++) {
+		nthw_iic_t *p_nthw_iic = nthw_iic_new();
+
+		if (p_nthw_iic) {
+			const int rc = nthw_iic_init(p_nthw_iic, p_fpga, i, 8);
+
+			if (rc == 0) {
+				nthw_iic_set_retry_params(p_nthw_iic, -1, 100, 100, 3, 3);
+				nthw_iic_scan(p_nthw_iic);
+			}
+
+			nthw_iic_delete(p_nthw_iic);
+			p_nthw_iic = NULL;
+		}
+	}
+
+	return 0;
+}
+
+int nthw_fpga_silabs_detect(nthw_fpga_t *p_fpga, const int n_instance_no, const int n_dev_addr,
+	const int n_page_reg_addr)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	uint64_t ident = -1;
+	int res = -1;
+
+	nthw_iic_t *p_nthw_iic = nthw_iic_new();
+
+	if (p_nthw_iic) {
+		uint8_t data;
+		uint8_t a_silabs_ident[8];
+		nthw_iic_init(p_nthw_iic, p_fpga, n_instance_no, 8);
+
+		data = 0;
+		/* switch to page 0 */
+		nthw_iic_write_data(p_nthw_iic, (uint8_t)n_dev_addr, (uint8_t)n_page_reg_addr, 1,
+			&data);
+		res = nthw_iic_read_data(p_nthw_iic, (uint8_t)n_dev_addr, 0x00,
+				sizeof(a_silabs_ident), a_silabs_ident);
+
+		if (res == 0) {
+			int i;
+
+			for (i = 0; i < (int)sizeof(a_silabs_ident); i++) {
+				ident <<= 8;
+				ident |= a_silabs_ident[i];
+			}
+		}
+
+		nthw_iic_delete(p_nthw_iic);
+		p_nthw_iic = NULL;
+
+		/* Conclude SiLabs part */
+		if (res == 0) {
+			if (a_silabs_ident[3] == 0x53) {
+				if (a_silabs_ident[2] == 0x40)
+					res = 5340;
+
+				else if (a_silabs_ident[2] == 0x41)
+					res = 5341;
+
+			} else if (a_silabs_ident[2] == 38) {
+				res = 5338;
+
+			} else {
+				res = -1;
+			}
+		}
+	}
+
+	NT_LOG(DBG, NTHW, "%s: %016" PRIX64 ": %d\n", p_adapter_id_str, ident, res);
+	return res;
+}
+
+/*
+ * Calculate CRC-16-CCITT of passed data
+ * CRC-16-CCITT ^16 + ^12 + ^5 + 1 (0x1021) (X.25, HDLC, XMODEM, Bluetooth,
+ *   SD, many others; known as CRC-CCITT)
+ */
+static uint16_t _crc16(uint8_t *buffer, size_t length)
+{
+	uint16_t seed = 0;
+
+	while (length--) {
+		seed = (uint16_t)(seed >> 8 | seed << 8);
+		seed = (uint16_t)(seed ^ *buffer++);
+		seed = (uint16_t)(seed ^ (seed & 0xff) >> 4);
+		seed = (uint16_t)(seed ^ seed << 8 << 4);
+		seed = (uint16_t)(seed ^ (seed & 0xff) << 4 << 1);
+	}
+
+	return seed;
+}
+
+int nthw_fpga_avr_probe(nthw_fpga_t *p_fpga, const int n_instance_no)
+{
+	struct fpga_info_s *p_fpga_info = p_fpga->p_fpga_info;
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+	nthw_spi_v3_t *p_avr_spi;
+	int res = -1;
+
+	p_avr_spi = nthw_spi_v3_new();
+
+	if (p_avr_spi) {
+		struct avr_vpd_info_s {
+			/* avr info */
+			uint32_t n_avr_spi_version;
+			uint8_t n_avr_fw_ver_major;
+			uint8_t n_avr_fw_ver_minor;
+			uint8_t n_avr_fw_ver_micro;
+			uint8_t a_avr_fw_ver_str[50];
+			uint8_t a_avr_fw_plat_id_str[20];
+
+			/* vpd_eeprom_t */
+			uint8_t psu_hw_version;
+			uint8_t vpd_pn[GEN2_PN_SIZE];
+			uint8_t vpd_pba[GEN2_PBA_SIZE];
+			uint8_t vpd_sn[GEN2_SN_SIZE];
+			uint8_t vpd_board_name[GEN2_BNAME_SIZE];
+			uint8_t vpd_platform_section[GEN2_PLATFORM_SIZE];
+
+			/* board_info_t aka vpd_platform_section: */
+			uint32_t product_family;/* uint8_t 1: capture, 2: Inline, 3: analysis */
+			uint32_t feature_mask;	/* Bit 0: OC192 capable */
+			uint32_t invfeature_mask;
+			uint8_t no_of_macs;
+			uint8_t mac_address[6];
+			uint16_t custom_id;
+			uint8_t user_id[8];
+			/*
+			 * Reserved NT operations to monitor the reprogram count of user_id with
+			 * vpduser
+			 */
+			uint16_t user_id_erase_write_count;
+
+			/*
+			 * AVR_OP_SYSINFO: struct version_sysinfo_request_container
+			 * Which version of the sysinfo container to retrieve. Set to zero to fetch
+			 * latest. Offset zero of latest always contain an uint8_t version info
+			 */
+			uint8_t sysinfo_container_version;
+
+			/* AVR_OP_SYSINFO: struct AvrLibcVersion */
+			/* The constant __AVR_LIBC_VERSION__ */
+			uint32_t sysinfo_avr_libc_version;
+
+			/* AVR_OP_SYSINFO: struct AvrLibcSignature */
+			uint8_t sysinfo_signature_0;	/* The constant SIGNATURE_0 */
+			uint8_t sysinfo_signature_1;	/* The constant SIGNATURE_1 */
+			uint8_t sysinfo_signature_2;	/* The constant SIGNATURE_2 */
+
+			/* AVR_OP_SYSINFO: struct AvrOs */
+			uint8_t sysinfo_spi_version;	/* SPI command layer version */
+			/*
+			 * Hardware revision. Locked to eeprom address zero. Is also available via
+			 * VPD read opcode (prior to v1.4b, this is required)
+			 */
+			uint8_t sysinfo_hw_revision;
+			/*
+			 * Number of ticks/second (Note: Be aware this may become zero if timer
+			 * module is rewritten to a tickles system!)
+			 */
+			uint8_t sysinfo_ticks_per_second;
+			uint32_t sysinfo_uptime;/* Uptime in seconds since last AVR reset */
+			uint8_t sysinfo_osccal;	/* OSCCAL value */
+
+			/*
+			 * Meta data concluded/calculated from req/reply
+			 */
+			bool b_feature_mask_valid;
+			bool b_crc16_valid;
+			uint16_t n_crc16_stored;
+			uint16_t n_crc16_calced;
+			uint64_t n_mac_val;
+		};
+
+		struct avr_vpd_info_s avr_vpd_info;
+		struct tx_rx_buf tx_buf;
+		struct tx_rx_buf rx_buf;
+		char rx_data[MAX_AVR_CONTAINER_SIZE];
+		uint32_t u32;
+
+		memset(&avr_vpd_info, 0, sizeof(avr_vpd_info));
+
+		nthw_spi_v3_init(p_avr_spi, p_fpga, n_instance_no);
+
+		/* AVR_OP_SPI_VERSION */
+		tx_buf.size = 0;
+		tx_buf.p_buf = NULL;
+		rx_buf.size = sizeof(u32);
+		rx_buf.p_buf = &u32;
+		u32 = 0;
+		res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SPI_VERSION, &tx_buf, &rx_buf);
+		avr_vpd_info.n_avr_spi_version = u32;
+		NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", p_adapter_id_str, n_instance_no,
+			avr_vpd_info.n_avr_spi_version);
+
+		/* AVR_OP_VERSION */
+		tx_buf.size = 0;
+		tx_buf.p_buf = NULL;
+		rx_buf.size = sizeof(rx_data);
+		rx_buf.p_buf = &rx_data;
+		res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_VERSION, &tx_buf, &rx_buf);
+
+		avr_vpd_info.n_avr_fw_ver_major = rx_data[0];
+		avr_vpd_info.n_avr_fw_ver_minor = rx_data[1];
+		avr_vpd_info.n_avr_fw_ver_micro = rx_data[2];
+		NT_LOG(DBG, NTHW, "%s: AVR%d: FW_VER: %c.%c.%c\n", p_adapter_id_str, n_instance_no,
+			avr_vpd_info.n_avr_fw_ver_major, avr_vpd_info.n_avr_fw_ver_minor,
+			avr_vpd_info.n_avr_fw_ver_micro);
+
+		memcpy(avr_vpd_info.a_avr_fw_ver_str, &rx_data[0 + 3],
+			sizeof(avr_vpd_info.a_avr_fw_ver_str));
+		NT_LOG(DBG, NTHW, "%s: AVR%d: FW_VER_STR: '%.*s'\n", p_adapter_id_str,
+			n_instance_no, (int)sizeof(avr_vpd_info.a_avr_fw_ver_str),
+			avr_vpd_info.a_avr_fw_ver_str);
+
+		memcpy(avr_vpd_info.a_avr_fw_plat_id_str, &rx_data[0 + 3 + 50],
+			sizeof(avr_vpd_info.a_avr_fw_plat_id_str));
+		NT_LOG(DBG, NTHW, "%s: AVR%d: FW_HW_ID_STR: '%.*s'\n", p_adapter_id_str,
+			n_instance_no, (int)sizeof(avr_vpd_info.a_avr_fw_plat_id_str),
+			avr_vpd_info.a_avr_fw_plat_id_str);
+
+		snprintf(p_fpga_info->nthw_hw_info.hw_plat_id_str,
+			sizeof(p_fpga_info->nthw_hw_info.hw_plat_id_str), "%s",
+			(char *)avr_vpd_info.a_avr_fw_plat_id_str);
+		p_fpga_info->nthw_hw_info
+		.hw_plat_id_str[sizeof(p_fpga_info->nthw_hw_info.hw_plat_id_str) - 1] = 0;
+
+		/* AVR_OP_SYSINFO_2 */
+		tx_buf.size = 0;
+		tx_buf.p_buf = NULL;
+		rx_buf.size = sizeof(rx_data);
+		rx_buf.p_buf = &rx_data;
+		res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SYSINFO_2, &tx_buf, &rx_buf);
+
+		if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 && rx_buf.size >= 16) {
+			if (rx_buf.size != 16) {
+				NT_LOG(WRN, NTHW,
+					"%s: AVR%d: SYSINFO2: reply is larger than expected: %04X %04X\n",
+					p_adapter_id_str, n_instance_no, rx_buf.size, 16);
+
+			} else {
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SYSINFO2: OK: res=%d sz=%d\n",
+					p_adapter_id_str, n_instance_no, res, rx_buf.size);
+			}
+
+			avr_vpd_info.sysinfo_container_version = rx_data[0];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: SYSINFO_REQ_VER: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_container_version);
+
+			memcpy(&avr_vpd_info.sysinfo_avr_libc_version, &rx_data[0 + 1],
+				sizeof(avr_vpd_info.sysinfo_avr_libc_version));
+			NT_LOG(DBG, NTHW, "%s: AVR%d: LIBC_VER: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_avr_libc_version);
+
+			avr_vpd_info.sysinfo_signature_0 = rx_data[5];
+			avr_vpd_info.sysinfo_signature_1 = rx_data[6];
+			avr_vpd_info.sysinfo_signature_2 = rx_data[7];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: SIGNATURE: %02x%02x%02x\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_signature_0,
+				avr_vpd_info.sysinfo_signature_1, avr_vpd_info.sysinfo_signature_2);
+
+			avr_vpd_info.sysinfo_spi_version = rx_data[8];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_spi_version);
+
+			avr_vpd_info.sysinfo_hw_revision = rx_data[9];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: HW_REV: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_hw_revision);
+
+			avr_vpd_info.sysinfo_ticks_per_second = rx_data[10];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: TICKS_PER_SEC: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_ticks_per_second);
+
+			memcpy(&avr_vpd_info.sysinfo_uptime, &rx_data[11],
+				sizeof(avr_vpd_info.sysinfo_uptime));
+			NT_LOG(DBG, NTHW, "%s: AVR%d: UPTIME: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_uptime);
+
+			avr_vpd_info.sysinfo_osccal = rx_data[15];
+			NT_LOG(DBG, NTHW, "%s: AVR%d: OSCCAL: %d\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.sysinfo_osccal);
+
+			{
+				bool b_spi_ver_match = (avr_vpd_info.n_avr_spi_version ==
+						avr_vpd_info.sysinfo_spi_version);
+				(void)b_spi_ver_match;
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER_TST: %s (%d %d)\n",
+					p_adapter_id_str, n_instance_no,
+					(b_spi_ver_match ? "OK" : "MISMATCH"),
+					avr_vpd_info.n_avr_spi_version,
+					avr_vpd_info.sysinfo_spi_version);
+			}
+			/* SYSINFO2: if response: only populate hw_id not hw_id_emulated */
+			p_fpga_info->nthw_hw_info.hw_id = avr_vpd_info.sysinfo_hw_revision;
+
+		} else {
+			/* AVR_OP_SYSINFO */
+			tx_buf.size = 0;
+			tx_buf.p_buf = NULL;
+			rx_buf.size = sizeof(rx_data);
+			rx_buf.p_buf = &rx_data;
+			res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_SYSINFO, &tx_buf, &rx_buf);
+
+			if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 && rx_buf.size >= 16) {
+				if (rx_buf.size != 16) {
+					NT_LOG(WRN, NTHW,
+						"%s: AVR%d: SYSINFO: reply is larger than expected: %04X %04X\n",
+						p_adapter_id_str, n_instance_no, rx_buf.size, 16);
+
+				} else {
+					NT_LOG(DBG, NTHW, "%s: AVR%d: SYSINFO: OK: res=%d sz=%d\n",
+						p_adapter_id_str, n_instance_no, res, rx_buf.size);
+				}
+
+				avr_vpd_info.sysinfo_container_version = rx_data[0];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SYSINFO_REQ_VER: %d\n",
+					p_adapter_id_str, n_instance_no,
+					avr_vpd_info.sysinfo_container_version);
+
+				memcpy(&avr_vpd_info.sysinfo_avr_libc_version, &rx_data[0 + 1],
+					sizeof(avr_vpd_info.sysinfo_avr_libc_version));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: LIBC_VER: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_avr_libc_version);
+
+				avr_vpd_info.sysinfo_signature_0 = rx_data[5];
+				avr_vpd_info.sysinfo_signature_1 = rx_data[6];
+				avr_vpd_info.sysinfo_signature_2 = rx_data[7];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SIGNATURE: %02x%02x%02x\n",
+					p_adapter_id_str, n_instance_no,
+					avr_vpd_info.sysinfo_signature_0,
+					avr_vpd_info.sysinfo_signature_1,
+					avr_vpd_info.sysinfo_signature_2);
+
+				avr_vpd_info.sysinfo_spi_version = rx_data[8];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_spi_version);
+
+				avr_vpd_info.sysinfo_hw_revision = rx_data[9];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: HW_REV: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_hw_revision);
+				NT_LOG(INF, NTHW, "%s: AVR%d: HW_REV: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_hw_revision);
+
+				avr_vpd_info.sysinfo_ticks_per_second = rx_data[10];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: TICKS_PER_SEC: %d\n",
+					p_adapter_id_str, n_instance_no,
+					avr_vpd_info.sysinfo_ticks_per_second);
+
+				memcpy(&avr_vpd_info.sysinfo_uptime, &rx_data[11],
+					sizeof(avr_vpd_info.sysinfo_uptime));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: UPTIME: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_uptime);
+
+				avr_vpd_info.sysinfo_osccal = rx_data[15];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: OSCCAL: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.sysinfo_osccal);
+
+				{
+					bool b_spi_ver_match = (avr_vpd_info.n_avr_spi_version ==
+							avr_vpd_info.sysinfo_spi_version);
+					(void)b_spi_ver_match;
+					NT_LOG(DBG, NTHW, "%s: AVR%d: SPI_VER_TST: %s (%d %d)\n",
+						p_adapter_id_str, n_instance_no,
+						(b_spi_ver_match ? "OK" : "MISMATCH"),
+						avr_vpd_info.n_avr_spi_version,
+						avr_vpd_info.sysinfo_spi_version);
+				}
+
+				p_fpga_info->nthw_hw_info.hw_id = avr_vpd_info.sysinfo_hw_revision;
+				p_fpga_info->nthw_hw_info.hw_id_emulated =
+					avr_vpd_info.sysinfo_hw_revision;
+
+			} else {
+				NT_LOG(ERR, NTHW, "%s: AVR%d: SYSINFO: NA: res=%d sz=%d\n",
+					p_adapter_id_str, n_instance_no, res, rx_buf.size);
+			}
+		}
+
+		/* AVR_OP_VPD_READ */
+		tx_buf.size = 0;
+		tx_buf.p_buf = NULL;
+		rx_buf.size = sizeof(rx_data);
+		rx_buf.p_buf = &rx_data;
+		res = nthw_spi_v3_transfer(p_avr_spi, AVR_OP_VPD_READ, &tx_buf, &rx_buf);
+
+		if (res == 0 && avr_vpd_info.n_avr_spi_version >= 3 &&
+			rx_buf.size >= GEN2_VPD_SIZE_TOTAL) {
+			avr_vpd_info.n_crc16_calced = _crc16(rx_buf.p_buf, rx_buf.size - 2);
+			memcpy(&avr_vpd_info.n_crc16_stored, &rx_data[rx_buf.size - 2],
+				sizeof(avr_vpd_info.n_crc16_stored));
+			NT_LOG(DBG, NTHW, "%s: AVR%d: VPD_CRC: %04X %04X\n", p_adapter_id_str,
+				n_instance_no, avr_vpd_info.n_crc16_stored,
+				avr_vpd_info.n_crc16_calced);
+
+			avr_vpd_info.b_crc16_valid =
+				(avr_vpd_info.n_crc16_stored == avr_vpd_info.n_crc16_calced);
+			NT_LOG(DBG, NTHW, "%s: AVR%d: CRC_TST: %s\n", p_adapter_id_str,
+				n_instance_no, (avr_vpd_info.b_crc16_valid ? "OK" : "ERROR"));
+
+			if (avr_vpd_info.b_crc16_valid) {
+				memcpy(&avr_vpd_info.psu_hw_version, &rx_data[0],
+					sizeof(avr_vpd_info.psu_hw_version));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: PSU_HW_VER: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.psu_hw_version);
+
+				memcpy(&avr_vpd_info.vpd_pn, &rx_data[0 + 1],
+					sizeof(avr_vpd_info.vpd_pn));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: PN: '%.*s'\n", p_adapter_id_str,
+					n_instance_no, GEN2_PN_SIZE, avr_vpd_info.vpd_pn);
+
+				memcpy(&avr_vpd_info.vpd_pba, &rx_data[0 + 1 + GEN2_PN_SIZE],
+					sizeof(avr_vpd_info.vpd_pba));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: PBA: '%.*s'\n", p_adapter_id_str,
+					n_instance_no, GEN2_PBA_SIZE, avr_vpd_info.vpd_pba);
+
+				memcpy(&avr_vpd_info.vpd_sn,
+					&rx_data[0 + 1 + GEN2_PN_SIZE + GEN2_PBA_SIZE],
+					sizeof(avr_vpd_info.vpd_sn));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: SN: '%.*s'\n", p_adapter_id_str,
+					n_instance_no, GEN2_SN_SIZE, avr_vpd_info.vpd_sn);
+
+				memcpy(&avr_vpd_info.vpd_board_name,
+					&rx_data[0 + 1 + GEN2_PN_SIZE + GEN2_PBA_SIZE +
+						GEN2_SN_SIZE],
+					sizeof(avr_vpd_info.vpd_board_name));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: BN: '%.*s'\n", p_adapter_id_str,
+					n_instance_no, GEN2_BNAME_SIZE,
+					avr_vpd_info.vpd_board_name);
+
+				union mac_u {
+					uint8_t a_u8[8];
+					uint16_t a_u16[4];
+					uint32_t a_u32[2];
+					uint64_t a_u64[1];
+				} mac;
+
+				/* vpd_platform_section */
+				uint8_t *p_vpd_board_info =
+					(uint8_t *)(&rx_data[1 + GEN2_PN_SIZE + GEN2_PBA_SIZE +
+							GEN2_SN_SIZE + GEN2_BNAME_SIZE]);
+				memcpy(&avr_vpd_info.product_family, &p_vpd_board_info[0],
+					sizeof(avr_vpd_info.product_family));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: PROD_FAM: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.product_family);
+
+				memcpy(&avr_vpd_info.feature_mask, &p_vpd_board_info[0 + 4],
+					sizeof(avr_vpd_info.feature_mask));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: FMSK_VAL: 0x%08X\n",
+					p_adapter_id_str, n_instance_no, avr_vpd_info.feature_mask);
+
+				memcpy(&avr_vpd_info.invfeature_mask, &p_vpd_board_info[0 + 4 + 4],
+					sizeof(avr_vpd_info.invfeature_mask));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: FMSK_INV: 0x%08X\n",
+					p_adapter_id_str, n_instance_no,
+					avr_vpd_info.invfeature_mask);
+
+				avr_vpd_info.b_feature_mask_valid =
+					(avr_vpd_info.feature_mask ==
+						~avr_vpd_info.invfeature_mask);
+				NT_LOG(DBG, NTHW, "%s: AVR%d: FMSK_TST: %s\n", p_adapter_id_str,
+					n_instance_no,
+					(avr_vpd_info.b_feature_mask_valid ? "OK" : "ERROR"));
+
+				memcpy(&avr_vpd_info.no_of_macs, &p_vpd_board_info[0 + 4 + 4 + 4],
+					sizeof(avr_vpd_info.no_of_macs));
+				NT_LOG(DBG, NTHW, "%s: AVR%d: NUM_MACS: %d\n", p_adapter_id_str,
+					n_instance_no, avr_vpd_info.no_of_macs);
+
+				memcpy(&avr_vpd_info.mac_address,
+					&p_vpd_board_info[0 + 4 + 4 + 4 + 1],
+					sizeof(avr_vpd_info.mac_address));
+				NT_LOG(DBG, NTHW,
+					"%s: AVR%d: MAC_ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
+					p_adapter_id_str, n_instance_no,
+					avr_vpd_info.mac_address[0], avr_vpd_info.mac_address[1],
+					avr_vpd_info.mac_address[2], avr_vpd_info.mac_address[3],
+					avr_vpd_info.mac_address[4], avr_vpd_info.mac_address[5]);
+
+				mac.a_u64[0] = 0;
+				memcpy(&mac.a_u8[2], &avr_vpd_info.mac_address,
+					sizeof(avr_vpd_info.mac_address));
+				{
+					const uint32_t u1 = ntohl(mac.a_u32[0]);
+
+					if (u1 != mac.a_u32[0]) {
+						const uint32_t u0 = ntohl(mac.a_u32[1]);
+						mac.a_u32[0] = u0;
+						mac.a_u32[1] = u1;
+					}
+				}
+				avr_vpd_info.n_mac_val = mac.a_u64[0];
+				NT_LOG(DBG, NTHW, "%s: AVR%d: MAC_U64: %012" PRIX64 "\n",
+					p_adapter_id_str, n_instance_no, avr_vpd_info.n_mac_val);
+			}
+
+			p_fpga_info->nthw_hw_info.vpd_info.mn_mac_addr_count =
+				avr_vpd_info.no_of_macs;
+			p_fpga_info->nthw_hw_info.vpd_info.mn_mac_addr_value =
+				avr_vpd_info.n_mac_val;
+			memcpy(p_fpga_info->nthw_hw_info.vpd_info.ma_mac_addr_octets,
+				avr_vpd_info.mac_address,
+				ARRAY_SIZE(p_fpga_info->nthw_hw_info.vpd_info.ma_mac_addr_octets));
+
+		} else {
+			NT_LOG(ERR, NTHW, "%s:%u: res=%d\n", __func__, __LINE__, res);
+			NT_LOG(ERR, NTHW, "%s: AVR%d: SYSINFO2: NA: res=%d sz=%d\n",
+				p_adapter_id_str, n_instance_no, res, rx_buf.size);
+		}
+	}
+
+	return res;
+}
+
+/*
+ * NT50B01, NT200A02, NT200A01-HWbuild2
+ */
+int nthw_fpga_si5340_clock_synth_init_fmt2(nthw_fpga_t *p_fpga, const uint8_t n_iic_addr,
+	const clk_profile_data_fmt2_t *p_clk_profile,
+	const int n_clk_profile_rec_cnt)
+{
+	int res;
+	nthw_iic_t *p_nthw_iic = nthw_iic_new();
+	nthw_si5340_t *p_nthw_si5340 = nthw_si5340_new();
+
+	assert(p_nthw_iic);
+	assert(p_nthw_si5340);
+	nthw_iic_init(p_nthw_iic, p_fpga, 0, 8);/* I2C cycle time 125Mhz ~ 8ns */
+
+	nthw_si5340_init(p_nthw_si5340, p_nthw_iic, n_iic_addr);/* si5340_u23_i2c_addr_7bit */
+	res = nthw_si5340_config_fmt2(p_nthw_si5340, p_clk_profile, n_clk_profile_rec_cnt);
+	nthw_si5340_delete(p_nthw_si5340);
+	p_nthw_si5340 = NULL;
+
+	return res;
+}
+
+int nthw_fpga_init(struct fpga_info_s *p_fpga_info)
+{
+	const char *const p_adapter_id_str = p_fpga_info->mp_adapter_id_str;
+
+	nthw_hif_t *p_nthw_hif = NULL;
+	nthw_pcie3_t *p_nthw_pcie3 = NULL;
+	nthw_rac_t *p_nthw_rac = NULL;
+	nthw_tsm_t *p_nthw_tsm = NULL;
+
+	mcu_info_t *p_mcu_info = &p_fpga_info->mcu_info;
+	(void)p_mcu_info;
+	uint64_t n_fpga_ident = 0;
+	nthw_fpga_mgr_t *p_fpga_mgr = NULL;
+	nthw_fpga_t *p_fpga = NULL;
+
+	char s_fpga_prod_ver_rev_str[32] = { 0 };
+
+	int res = 0;
+
+	assert(p_fpga_info);
+
+	{
+		const uint64_t n_fpga_ident = nthw_fpga_read_ident(p_fpga_info);
+		const uint32_t n_fpga_build_time = nthw_fpga_read_buildtime(p_fpga_info);
+		const int n_fpga_type_id = nthw_fpga_extract_type_id(n_fpga_ident);
+		const int n_fpga_prod_id = nthw_fpga_extract_prod_id(n_fpga_ident);
+		const int n_fpga_ver_id = nthw_fpga_extract_ver_id(n_fpga_ident);
+		const int n_fpga_rev_id = nthw_fpga_extract_rev_id(n_fpga_ident);
+
+		p_fpga_info->n_fpga_ident = n_fpga_ident;
+		p_fpga_info->n_fpga_type_id = n_fpga_type_id;
+		p_fpga_info->n_fpga_prod_id = n_fpga_prod_id;
+		p_fpga_info->n_fpga_ver_id = n_fpga_ver_id;
+		p_fpga_info->n_fpga_rev_id = n_fpga_rev_id;
+		p_fpga_info->n_fpga_build_time = n_fpga_build_time;
+
+		snprintf(s_fpga_prod_ver_rev_str, sizeof(s_fpga_prod_ver_rev_str),
+			"%04d-%04d-%02d-%02d", n_fpga_type_id, n_fpga_prod_id, n_fpga_ver_id,
+			n_fpga_rev_id);
+
+		NT_LOG(INF, NTHW, "%s: FPGA %s (%" PRIX64 ") [%08X]\n", p_adapter_id_str,
+			s_fpga_prod_ver_rev_str, n_fpga_ident, n_fpga_build_time);
+	}
+
+	n_fpga_ident = p_fpga_info->n_fpga_ident;
+
+	p_fpga_mgr = nthw_fpga_mgr_new();
+	nthw_fpga_mgr_init(p_fpga_mgr, nthw_fpga_instances,
+		(const void *)sa_nthw_fpga_mod_str_map);
+	nthw_fpga_mgr_log_dump(p_fpga_mgr);
+	p_fpga = nthw_fpga_mgr_query_fpga(p_fpga_mgr, n_fpga_ident, p_fpga_info);
+	p_fpga_info->mp_fpga = p_fpga;
+
+	if (p_fpga == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Unsupported FPGA: %s (%08X)\n", p_adapter_id_str,
+			s_fpga_prod_ver_rev_str, p_fpga_info->n_fpga_build_time);
+		return -1;
+	}
+
+	if (p_fpga_mgr) {
+		nthw_fpga_mgr_delete(p_fpga_mgr);
+		p_fpga_mgr = NULL;
+	}
+
+	/* Read Fpga param info */
+	nthw_fpga_get_param_info(p_fpga_info, p_fpga);
+
+	/* debug: report params */
+	NT_LOG(DBG, NTHW, "%s: NT_NIMS=%d\n", p_adapter_id_str, p_fpga_info->n_nims);
+	NT_LOG(DBG, NTHW, "%s: NT_PHY_PORTS=%d\n", p_adapter_id_str, p_fpga_info->n_phy_ports);
+	NT_LOG(DBG, NTHW, "%s: NT_PHY_QUADS=%d\n", p_adapter_id_str, p_fpga_info->n_phy_quads);
+	NT_LOG(DBG, NTHW, "%s: NT_RX_PORTS=%d\n", p_adapter_id_str, p_fpga_info->n_rx_ports);
+	NT_LOG(DBG, NTHW, "%s: NT_TX_PORTS=%d\n", p_adapter_id_str, p_fpga_info->n_tx_ports);
+	NT_LOG(DBG, NTHW, "%s: nProfile=%d\n", p_adapter_id_str, (int)p_fpga_info->profile);
+	NT_LOG(DBG, NTHW, "%s: bHasMcu=%d\n", p_adapter_id_str, p_mcu_info->mb_has_mcu);
+	NT_LOG(DBG, NTHW, "%s: McuType=%d\n", p_adapter_id_str, p_mcu_info->mn_mcu_type);
+	NT_LOG(DBG, NTHW, "%s: McuDramSize=%d\n", p_adapter_id_str, p_mcu_info->mn_mcu_dram_size);
+
+	p_nthw_rac = nthw_rac_new();
+
+	if (p_nthw_rac == NULL) {
+		NT_LOG(ERR, NTHW, "%s: Unsupported FPGA: RAC is not found: %s (%08X)\n",
+			p_adapter_id_str, s_fpga_prod_ver_rev_str, p_fpga_info->n_fpga_build_time);
+		return -1;
+	}
+
+	nthw_rac_init(p_nthw_rac, p_fpga, p_fpga_info);
+	nthw_rac_rab_flush(p_nthw_rac);
+	p_fpga_info->mp_nthw_rac = p_nthw_rac;
+
+	/* special case: values below 0x100 will disable debug on RAC communication */
+	{
+		const int n_fpga_initial_debug_mode = p_fpga_info->n_fpga_debug_mode;
+		nthw_fpga_set_debug_mode(p_fpga, n_fpga_initial_debug_mode);
+	}
+	bool included = true;
+	struct nt200a0x_ops *nt200a0x_ops = get_nt200a0x_ops();
+	struct nt50b0x_ops *nt50b0x_ops = get_nt50b0x_ops();
+	struct nt400dxx_ops *nt400dxx_ops = get_nt400dxx_ops();
+
+	switch (p_fpga_info->n_nthw_adapter_id) {
+	case NT_HW_ADAPTER_ID_NT200A01:	/* fallthrough */
+	case NT_HW_ADAPTER_ID_NT200A02:
+		if (nt200a0x_ops != NULL)
+			res = nt200a0x_ops->nthw_fpga_nt200a0x_init(p_fpga_info);
+
+		else
+			included = false;
+
+		break;
+
+	case NT_HW_ADAPTER_ID_NT50B01:
+		if (nt50b0x_ops)
+			res = nt50b0x_ops->nthw_fpga_nt50b0x_init(p_fpga_info);
+
+		else
+			included = false;
+
+		break;
+
+	case NT_HW_ADAPTER_ID_NT400D11:
+		if (nt400dxx_ops != NULL)
+			res = nt400dxx_ops->nthw_fpga_nt400dxx_init(p_fpga_info);
+
+		else
+			included = false;
+
+		break;
+
+	default:
+		NT_LOG(ERR, NTHW, "%s: Unsupported HW product id: %d\n", p_adapter_id_str,
+			p_fpga_info->n_nthw_adapter_id);
+		res = -1;
+		break;
+	}
+
+	if (!included) {
+		NT_LOG(ERR, NTHW, "%s: NOT INCLUDED HW product: %d\n", p_adapter_id_str,
+			p_fpga_info->n_nthw_adapter_id);
+		res = -1;
+	}
+
+	if (res) {
+		NT_LOG(ERR, NTHW, "%s: status: 0x%08X\n", p_adapter_id_str, res);
+		return res;
+	}
+
+	res = nthw_pcie3_init(NULL, p_fpga, 0);	/* Probe for module */
+
+	if (res == 0) {
+		p_nthw_pcie3 = nthw_pcie3_new();
+
+		if (p_nthw_pcie3) {
+			res = nthw_pcie3_init(p_nthw_pcie3, p_fpga, 0);
+
+			if (res == 0) {
+				NT_LOG(DBG, NTHW, "%s: Pcie3 module found\n", p_adapter_id_str);
+				nthw_pcie3_trigger_sample_time(p_nthw_pcie3);
+
+			} else {
+				nthw_pcie3_delete(p_nthw_pcie3);
+				p_nthw_pcie3 = NULL;
+			}
+		}
+
+		p_fpga_info->mp_nthw_pcie3 = p_nthw_pcie3;
+	}
+
+	if (p_nthw_pcie3 == NULL) {
+		p_nthw_hif = nthw_hif_new();
+
+		if (p_nthw_hif) {
+			res = nthw_hif_init(p_nthw_hif, p_fpga, 0);
+
+			if (res == 0) {
+				NT_LOG(DBG, NTHW, "%s: Hif module found\n", p_adapter_id_str);
+				nthw_hif_trigger_sample_time(p_nthw_hif);
+
+			} else {
+				nthw_hif_delete(p_nthw_hif);
+				p_nthw_hif = NULL;
+			}
+		}
+	}
+
+	p_fpga_info->mp_nthw_hif = p_nthw_hif;
+
+	p_nthw_tsm = nthw_tsm_new();
+
+	if (p_nthw_tsm) {
+		nthw_tsm_init(p_nthw_tsm, p_fpga, 0);
+
+		nthw_tsm_set_config_ts_format(p_nthw_tsm, 1);	/* 1 = TSM: TS format native */
+
+		/* Timer T0 - stat toggle timer */
+		nthw_tsm_set_timer_t0_enable(p_nthw_tsm, false);
+		nthw_tsm_set_timer_t0_max_count(p_nthw_tsm, 50 * 1000 * 1000);	/* ns */
+		nthw_tsm_set_timer_t0_enable(p_nthw_tsm, true);
+
+		/* Timer T1 - keep alive timer */
+		nthw_tsm_set_timer_t1_enable(p_nthw_tsm, false);
+		nthw_tsm_set_timer_t1_max_count(p_nthw_tsm, 100 * 1000 * 1000);	/* ns */
+		nthw_tsm_set_timer_t1_enable(p_nthw_tsm, true);
+	}
+
+	p_fpga_info->mp_nthw_tsm = p_nthw_tsm;
+
+	/* TSM sample triggering: test validation... */
+#if defined(DEBUG) && (1)
+	{
+		uint64_t n_time, n_ts;
+		int i;
+
+		for (i = 0; i < 4; i++) {
+			if (p_nthw_hif)
+				nthw_hif_trigger_sample_time(p_nthw_hif);
+
+			else if (p_nthw_pcie3)
+				nthw_pcie3_trigger_sample_time(p_nthw_pcie3);
+
+			nthw_tsm_get_time(p_nthw_tsm, &n_time);
+			nthw_tsm_get_ts(p_nthw_tsm, &n_ts);
+
+			NT_LOG(DBG, NTHW, "%s: TSM time: %016" PRIX64 " %016" PRIX64 "\n",
+				p_adapter_id_str, n_time, n_ts);
+
+			nt_os_wait_usec(1000);
+		}
+	}
+#endif
+
+	return res;
+}
+
+int nthw_fpga_shutdown(struct fpga_info_s *p_fpga_info)
+{
+	int res = -1;
+
+	if (p_fpga_info) {
+		if (p_fpga_info && p_fpga_info->mp_nthw_rac)
+			res = nthw_rac_rab_reset(p_fpga_info->mp_nthw_rac);
+	}
+
+	return res;
+}
+
+static struct nt200a0x_ops *nt200a0x_ops;
+
+void register_nt200a0x_ops(struct nt200a0x_ops *ops)
+{
+	nt200a0x_ops = ops;
+}
+
+struct nt200a0x_ops *get_nt200a0x_ops(void)
+{
+	return nt200a0x_ops;
+}
+
+static struct nt50b0x_ops *nt50b0x_ops;
+
+struct nt50b0x_ops *get_nt50b0x_ops(void)
+{
+	return nt50b0x_ops;
+}
+
+static struct nt400dxx_ops *nt400dxx_ops;
+
+struct nt400dxx_ops *get_nt400dxx_ops(void)
+{
+	return nt400dxx_ops;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c
new file mode 100644
index 0000000000..e0fb0ec3d8
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_fpga_rst.c
@@ -0,0 +1,10 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_fpga.h"
+
+#include "nthw_fpga_rst.h"
diff --git a/drivers/net/ntnic/nthw/core/nthw_hif.c b/drivers/net/ntnic/nthw/core/nthw_hif.c
new file mode 100644
index 0000000000..b35b456528
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_hif.c
@@ -0,0 +1,312 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_hif.h"
+
+nthw_hif_t *nthw_hif_new(void)
+{
+	nthw_hif_t *p = malloc(sizeof(nthw_hif_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_hif_t));
+
+	return p;
+}
+
+void nthw_hif_delete(nthw_hif_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_hif_t));
+		free(p);
+	}
+}
+
+int nthw_hif_init(nthw_hif_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_HIF, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: HIF %d: no such instance\n",
+			p_fpga->p_fpga_info->mp_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_hif = mod;
+
+	/* default for (Xilinx-based) products until august 2022: (1e6/4000 = 250 MHz) */
+	p->mn_fpga_param_hif_per_ps = nthw_fpga_get_product_param(p->mp_fpga, NT_HIF_PER_PS, 4000);
+	p->mn_fpga_hif_ref_clk_freq =
+		(uint32_t)(1000000000000ULL / (unsigned int)p->mn_fpga_param_hif_per_ps);
+
+	p->mp_reg_prod_id_lsb = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_LSB);
+	p->mp_fld_prod_id_lsb_rev_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_REV_ID);
+	p->mp_fld_prod_id_lsb_ver_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_VER_ID);
+	p->mp_fld_prod_id_lsb_group_id =
+		nthw_register_get_field(p->mp_reg_prod_id_lsb, HIF_PROD_ID_LSB_GROUP_ID);
+
+	p->mp_reg_prod_id_msb = nthw_module_get_register(p->mp_mod_hif, HIF_PROD_ID_MSB);
+	p->mp_fld_prod_id_msb_type_id =
+		nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_TYPE_ID);
+	p->mp_fld_prod_id_msb_build_no =
+		nthw_register_get_field(p->mp_reg_prod_id_msb, HIF_PROD_ID_MSB_BUILD_NO);
+
+	p->mp_reg_build_time = nthw_module_get_register(p->mp_mod_hif, HIF_BUILD_TIME);
+	p->mp_fld_build_time = nthw_register_get_field(p->mp_reg_build_time, HIF_BUILD_TIME_TIME);
+
+	p->mn_fpga_id_prod = nthw_field_get_updated(p->mp_fld_prod_id_lsb_group_id);
+	p->mn_fpga_id_ver = nthw_field_get_updated(p->mp_fld_prod_id_lsb_ver_id);
+	p->mn_fpga_id_rev = nthw_field_get_updated(p->mp_fld_prod_id_lsb_rev_id);
+	p->mn_fpga_id_build_no = nthw_field_get_updated(p->mp_fld_prod_id_msb_build_no);
+	p->mn_fpga_id_item = nthw_field_get_updated(p->mp_fld_prod_id_msb_type_id);
+
+	NT_LOG(DBG, NTHW, "%s: HIF %d: %s: %d-%d-%d-%d-%d\n", p_adapter_id_str, p->mn_instance,
+		__func__, p->mn_fpga_id_item, p->mn_fpga_id_prod, p->mn_fpga_id_ver,
+		p->mn_fpga_id_rev, p->mn_fpga_id_build_no);
+	NT_LOG(DBG, NTHW, "%s: HIF %d: %s: HIF ref clock: %d Hz (%d ticks/ps)\n", p_adapter_id_str,
+		p->mn_instance, __func__, p->mn_fpga_hif_ref_clk_freq, p->mn_fpga_param_hif_per_ps);
+
+	p->mp_reg_build_seed = NULL;	/* Reg/Fld not present on HIF */
+
+	if (p->mp_reg_build_seed)
+		p->mp_fld_build_seed = NULL;	/* Reg/Fld not present on HIF */
+	else
+		p->mp_fld_build_seed = NULL;
+
+	p->mp_reg_core_speed = NULL;	/* Reg/Fld not present on HIF */
+
+	if (p->mp_reg_core_speed) {
+		p->mp_fld_core_speed = NULL;	/* Reg/Fld not present on HIF */
+		p->mp_fld_ddr3_speed = NULL;	/* Reg/Fld not present on HIF */
+
+	} else {
+		p->mp_reg_core_speed = NULL;
+		p->mp_fld_core_speed = NULL;
+		p->mp_fld_ddr3_speed = NULL;
+	}
+
+	/* Optional registers since: 2018-04-25 */
+	p->mp_reg_int_mask = NULL;	/* Reg/Fld not present on HIF */
+	p->mp_reg_int_clr = NULL;	/* Reg/Fld not present on HIF */
+	p->mp_reg_int_force = NULL;	/* Reg/Fld not present on HIF */
+
+	p->mp_fld_int_mask_timer = NULL;
+	p->mp_fld_int_clr_timer = NULL;
+	p->mp_fld_int_force_timer = NULL;
+
+	p->mp_fld_int_mask_port = NULL;
+	p->mp_fld_int_clr_port = NULL;
+	p->mp_fld_int_force_port = NULL;
+
+	p->mp_fld_int_mask_pps = NULL;
+	p->mp_fld_int_clr_pps = NULL;
+	p->mp_fld_int_force_pps = NULL;
+
+	p->mp_reg_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_CONTROL);
+	p->mp_fld_ctrl_fsr = nthw_register_query_field(p->mp_reg_ctrl, HIF_CONTROL_FSR);
+
+	p->mp_reg_stat_ctrl = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_CTRL);
+	p->mp_fld_stat_ctrl_ena =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_ENA);
+	p->mp_fld_stat_ctrl_req =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, HIF_STAT_CTRL_STAT_REQ);
+
+	p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_RX);
+	p->mp_fld_stat_rx_counter =
+		nthw_register_get_field(p->mp_reg_stat_rx, HIF_STAT_RX_COUNTER);
+
+	p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_TX);
+	p->mp_fld_stat_tx_counter =
+		nthw_register_get_field(p->mp_reg_stat_tx, HIF_STAT_TX_COUNTER);
+
+	p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_hif, HIF_STAT_REFCLK);
+	p->mp_fld_stat_ref_clk_ref_clk =
+		nthw_register_get_field(p->mp_reg_stat_ref_clk, HIF_STAT_REFCLK_REFCLK250);
+
+	p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS);
+
+	if (p->mp_reg_status) {
+		p->mp_fld_status_tags_in_use =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE);
+		p->mp_fld_status_wr_err =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_WR_ERR);
+		p->mp_fld_status_rd_err =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_RD_ERR);
+
+	} else {
+		p->mp_reg_status = nthw_module_query_register(p->mp_mod_hif, HIF_STATUS);
+		p->mp_fld_status_tags_in_use =
+			nthw_register_query_field(p->mp_reg_status, HIF_STATUS_TAGS_IN_USE);
+		p->mp_fld_status_wr_err = NULL;
+		p->mp_fld_status_rd_err = NULL;
+	}
+
+	p->mp_reg_pci_test0 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST0);
+	p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, HIF_TEST0_DATA);
+
+	p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_hif, HIF_TEST1);
+	p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, HIF_TEST1_DATA);
+
+	/* Module::Version({2, 0})+ */
+	p->mp_reg_pci_test2 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST2);
+
+	if (p->mp_reg_pci_test2)
+		p->mp_fld_pci_test2 = nthw_register_get_field(p->mp_reg_pci_test2, HIF_TEST2_DATA);
+
+	else
+		p->mp_fld_pci_test2 = NULL;
+
+	/* Module::Version({1, 2})+ */
+	p->mp_reg_pci_test3 = nthw_module_query_register(p->mp_mod_hif, HIF_TEST3);
+
+	if (p->mp_reg_pci_test3)
+		p->mp_fld_pci_test3 = nthw_register_get_field(p->mp_reg_pci_test3, HIF_TEST3_DATA);
+
+	else
+		p->mp_fld_pci_test3 = NULL;
+
+	/* Required to run TSM */
+	p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_hif, HIF_SAMPLE_TIME);
+
+	if (p->mp_reg_sample_time) {
+		p->mp_fld_sample_time = nthw_register_get_field(p->mp_reg_sample_time,
+				HIF_SAMPLE_TIME_SAMPLE_TIME);
+
+	} else {
+		p->mp_fld_sample_time = NULL;
+	}
+
+	/* We need to optimize PCIe3 TLP-size read-request and extended tag usage */
+	{
+		p->mp_reg_config = nthw_module_query_register(p->mp_mod_hif, HIF_CONFIG);
+
+		if (p->mp_reg_config) {
+			p->mp_fld_max_tlp =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_TLP);
+			p->mp_fld_max_read =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_MAX_READ);
+			p->mp_fld_ext_tag =
+				nthw_register_get_field(p->mp_reg_config, HIF_CONFIG_EXT_TAG);
+
+		} else {
+			p->mp_fld_max_tlp = NULL;
+			p->mp_fld_max_read = NULL;
+			p->mp_fld_ext_tag = NULL;
+		}
+	}
+
+	return 0;
+}
+
+int nthw_hif_trigger_sample_time(nthw_hif_t *p)
+{
+	nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead);
+
+	return 0;
+}
+
+int nthw_hif_get_stat(nthw_hif_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint64_t *p_tags_in_use, uint64_t *p_rd_err, uint64_t *p_wr_err)
+{
+	*p_rx_cnt = nthw_field_get_updated(p->mp_fld_stat_rx_counter);
+	*p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter);
+
+	*p_ref_clk_cnt = nthw_field_get_updated(p->mp_fld_stat_ref_clk_ref_clk);
+
+	*p_tg_unit_size = NTHW_TG_CNT_SIZE;
+	*p_tg_ref_freq = p->mn_fpga_hif_ref_clk_freq;
+
+	*p_tags_in_use = (p->mp_fld_status_tags_in_use
+			? nthw_field_get_updated(p->mp_fld_status_tags_in_use)
+			: 0);
+
+	*p_rd_err =
+		(p->mp_fld_status_rd_err ? nthw_field_get_updated(p->mp_fld_status_rd_err) : 0);
+	*p_wr_err =
+		(p->mp_fld_status_wr_err ? nthw_field_get_updated(p->mp_fld_status_wr_err) : 0);
+
+	return 0;
+}
+
+int nthw_hif_get_stat_rate(nthw_hif_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tags_in_use,
+	uint64_t *p_rd_err_cnt, uint64_t *p_wr_err_cnt)
+{
+	uint32_t rx_cnt, tx_cnt, ref_clk_cnt, tg_unit_size, tg_ref_freq;
+	uint64_t n_tags_in_use, n_rd_err, n_wr_err;
+
+	nthw_hif_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, &tg_ref_freq,
+		&n_tags_in_use, &n_rd_err, &n_wr_err);
+
+	*p_tags_in_use = n_tags_in_use;
+
+	if (n_rd_err)
+		(*p_rd_err_cnt)++;
+
+	if (n_wr_err)
+		(*p_wr_err_cnt)++;
+
+	if (ref_clk_cnt) {
+		uint64_t rx_rate;
+		uint64_t tx_rate;
+
+		*p_ref_clk_cnt = ref_clk_cnt;
+
+		rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_rx_rate = rx_rate;
+
+		tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_tx_rate = tx_rate;
+
+	} else {
+		*p_pci_rx_rate = 0;
+		*p_pci_tx_rate = 0;
+		*p_ref_clk_cnt = 0;
+	}
+
+	return 0;
+}
+
+int nthw_hif_stat_req_enable(nthw_hif_t *p)
+{
+	nthw_field_set_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_hif_stat_req_disable(nthw_hif_t *p)
+{
+	nthw_field_clr_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_hif_end_point_counters_sample(nthw_hif_t *p, struct nthw_hif_end_point_counters *epc)
+{
+	assert(epc);
+
+	/* Get stat rate and maintain rx/tx min/max */
+	nthw_hif_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt,
+		&epc->n_tags_in_use, &epc->n_rd_err, &epc->n_wr_err);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_iic.c b/drivers/net/ntnic/nthw/core/nthw_iic.c
new file mode 100644
index 0000000000..cdaee20e8a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_iic.c
@@ -0,0 +1,529 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_iic.h"
+
+#define I2C_TRANSMIT_WR (0x00)
+#define I2C_TRANSMIT_RD (0x01)
+
+#define I2C_WAIT_US(x) nt_os_wait_usec(x)
+
+/*
+ * Minimum timing values for I2C for a Marvel 88E11111 Phy.
+ * This Phy is used in many Trispeed NIMs.
+ * In order to access this Phy, the I2C clock speed is needed to be set to 100KHz.
+ */
+static const uint32_t SUSTA = 4700;	/* ns */
+static const uint32_t SUSTO = 4000;	/* ns */
+static const uint32_t HDSTA = 4000;	/* ns */
+static const uint32_t SUDAT = 250;	/* ns */
+static const uint32_t BUF = 4700;	/* ns */
+static const uint32_t HIGH = 4000;	/* ns */
+static const uint32_t LOW = 4700;	/* ns */
+static const uint32_t HDDAT = 300;	/* ns */
+
+static int nthw_iic_reg_control_txfifo_reset(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_txfifo_reset);
+
+	nthw_field_set_all(p->mp_fld_cr_txfifo_reset);
+	nthw_field_flush_register(p->mp_fld_cr_txfifo_reset);
+
+	nthw_field_clr_all(p->mp_fld_cr_txfifo_reset);
+	nthw_field_flush_register(p->mp_fld_cr_txfifo_reset);
+
+	return 0;
+}
+
+static int nthw_iic_reg_tx_fifo_write(nthw_iic_t *p, uint32_t data, bool start, bool stop)
+{
+	if (start)
+		nthw_field_set_all(p->mp_fld_tx_fifo_start);
+
+	else
+		nthw_field_clr_all(p->mp_fld_tx_fifo_start);
+
+	if (stop)
+		nthw_field_set_all(p->mp_fld_tx_fifo_stop);
+
+	else
+		nthw_field_clr_all(p->mp_fld_tx_fifo_stop);
+
+	nthw_field_set_val32(p->mp_fld_tx_fifo_txdata, data);
+
+	nthw_register_flush(p->mp_reg_tx_fifo, 1);
+
+	return 0;
+}
+
+static int nthw_iic_reg_read_i2c_rx_fifo(nthw_iic_t *p, uint8_t *p_data)
+{
+	assert(p_data);
+
+	*p_data = (uint8_t)nthw_field_get_updated(p->mp_fld_rx_fifo_rxdata);
+
+	return 0;
+}
+
+static int nthw_iic_reg_softr(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+	nthw_field_set_val_flush32(p->mp_fld_softr_rkey, 0x0A);
+
+	return 0;
+}
+
+static int nthw_iic_reg_enable(nthw_iic_t *p)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+	nthw_field_set_flush(p->mp_fld_cr_en);
+
+	return 0;
+}
+
+static int nthw_iic_reg_busbusy(nthw_iic_t *p, bool *pb_flag)
+{
+	assert(pb_flag);
+
+	*pb_flag = nthw_field_get_updated(p->mp_fld_sr_bb) ? true : false;
+
+	return 0;
+}
+
+static int nthw_iic_reg_rxfifo_empty(nthw_iic_t *p, bool *pb_flag)
+{
+	assert(pb_flag);
+
+	*pb_flag = nthw_field_get_updated(p->mp_fld_sr_rxfifo_empty) ? true : false;
+
+	return 0;
+}
+
+/*
+ * n_iic_cycle_time is the I2C clock cycle time in ns ie 125MHz = 8ns
+ */
+static int nthw_iic_reg_set_timing(nthw_iic_t *p, uint32_t n_iic_cycle_time)
+{
+	uint32_t val;
+
+	val = SUSTA / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsusta, &val, 1);
+
+	val = SUSTO / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsusto, &val, 1);
+
+	val = HDSTA / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thdsta, &val, 1);
+
+	val = SUDAT / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tsudat, &val, 1);
+
+	val = BUF / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tbuf, &val, 1);
+
+	val = HIGH / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thigh, &val, 1);
+
+	val = LOW / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_tlow, &val, 1);
+
+	val = HDDAT / n_iic_cycle_time;
+	nthw_field_set_val_flush(p->mp_fld_thddat, &val, 1);
+
+	return 0;
+}
+
+nthw_iic_t *nthw_iic_new(void)
+{
+	nthw_iic_t *p = malloc(sizeof(nthw_iic_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_iic_t));
+
+	return p;
+}
+
+int nthw_iic_init(nthw_iic_t *p, nthw_fpga_t *p_fpga, int n_iic_instance,
+	uint32_t n_iic_cycle_time)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_IIC, n_iic_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: I2C %d: no such instance\n", p_adapter_id_str,
+			n_iic_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_iic_instance = n_iic_instance;
+
+	p->mn_iic_cycle_time = n_iic_cycle_time;
+
+	nthw_iic_set_retry_params(p, -1, -1, -1, -1, -1);
+
+	p->mp_mod_iic = mod;
+
+	/* I2C is a primary communication channel - turn off debug by default */
+	nthw_module_set_debug_mode(p->mp_mod_iic, 0x00);
+
+	p->mp_reg_tsusta = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTA);
+	p->mp_fld_tsusta = nthw_register_get_field(p->mp_reg_tsusta, IIC_TSUSTA_TSUSTA_VAL);
+
+	p->mp_reg_tsusto = nthw_module_get_register(p->mp_mod_iic, IIC_TSUSTO);
+	p->mp_fld_tsusto = nthw_register_get_field(p->mp_reg_tsusto, IIC_TSUSTO_TSUSTO_VAL);
+
+	p->mp_reg_thdsta = nthw_module_get_register(p->mp_mod_iic, IIC_THDSTA);
+	p->mp_fld_thdsta = nthw_register_get_field(p->mp_reg_thdsta, IIC_THDSTA_THDSTA_VAL);
+
+	p->mp_reg_tsudat = nthw_module_get_register(p->mp_mod_iic, IIC_TSUDAT);
+	p->mp_fld_tsudat = nthw_register_get_field(p->mp_reg_tsudat, IIC_TSUDAT_TSUDAT_VAL);
+
+	p->mp_reg_tbuf = nthw_module_get_register(p->mp_mod_iic, IIC_TBUF);
+	p->mp_fld_tbuf = nthw_register_get_field(p->mp_reg_tbuf, IIC_TBUF_TBUF_VAL);
+
+	p->mp_reg_thigh = nthw_module_get_register(p->mp_mod_iic, IIC_THIGH);
+	p->mp_fld_thigh = nthw_register_get_field(p->mp_reg_thigh, IIC_THIGH_THIGH_VAL);
+
+	p->mp_reg_tlow = nthw_module_get_register(p->mp_mod_iic, IIC_TLOW);
+	p->mp_fld_tlow = nthw_register_get_field(p->mp_reg_tlow, IIC_TLOW_TLOW_VAL);
+
+	p->mp_reg_thddat = nthw_module_get_register(p->mp_mod_iic, IIC_THDDAT);
+	p->mp_fld_thddat = nthw_register_get_field(p->mp_reg_thddat, IIC_THDDAT_THDDAT_VAL);
+
+	p->mp_reg_cr = nthw_module_get_register(p->mp_mod_iic, IIC_CR);
+	p->mp_fld_cr_en = nthw_register_get_field(p->mp_reg_cr, IIC_CR_EN);
+	p->mp_fld_cr_msms = nthw_register_get_field(p->mp_reg_cr, IIC_CR_MSMS);
+	p->mp_fld_cr_txfifo_reset = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXFIFO_RESET);
+	p->mp_fld_cr_txak = nthw_register_get_field(p->mp_reg_cr, IIC_CR_TXAK);
+
+	p->mp_reg_sr = nthw_module_get_register(p->mp_mod_iic, IIC_SR);
+	p->mp_fld_sr_bb = nthw_register_get_field(p->mp_reg_sr, IIC_SR_BB);
+	p->mp_fld_sr_rxfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_FULL);
+	p->mp_fld_sr_rxfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_RXFIFO_EMPTY);
+	p->mp_fld_sr_txfifo_full = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_FULL);
+	p->mp_fld_sr_txfifo_empty = nthw_register_get_field(p->mp_reg_sr, IIC_SR_TXFIFO_EMPTY);
+
+	p->mp_reg_tx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_TX_FIFO);
+	p->mp_fld_tx_fifo_txdata = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_TXDATA);
+	p->mp_fld_tx_fifo_start = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_START);
+	p->mp_fld_tx_fifo_stop = nthw_register_get_field(p->mp_reg_tx_fifo, IIC_TX_FIFO_STOP);
+
+	p->mp_reg_rx_fifo_pirq = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO_PIRQ);
+	p->mp_fld_rx_fifo_pirq_cmp_val =
+		nthw_register_get_field(p->mp_reg_rx_fifo_pirq, IIC_RX_FIFO_PIRQ_CMP_VAL);
+
+	p->mp_reg_rx_fifo = nthw_module_get_register(p->mp_mod_iic, IIC_RX_FIFO);
+	p->mp_fld_rx_fifo_rxdata = nthw_register_get_field(p->mp_reg_rx_fifo, IIC_RX_FIFO_RXDATA);
+
+	p->mp_reg_softr = nthw_module_get_register(p->mp_mod_iic, IIC_SOFTR);
+	p->mp_fld_softr_rkey = nthw_register_get_field(p->mp_reg_softr, IIC_SOFTR_RKEY);
+
+	/*
+	 * Initialize I2C controller by applying soft reset and enable the controller
+	 */
+	nthw_iic_reg_softr(p);
+	/* Enable the controller */
+	nthw_iic_reg_enable(p);
+
+	/* Setup controller timing */
+	if (p->mn_iic_cycle_time) {
+		NT_LOG(DBG, NTHW, "%s: I2C%d: cycletime=%d\n", p_adapter_id_str,
+			p->mn_iic_instance, p->mn_iic_cycle_time);
+		nthw_iic_reg_set_timing(p, p->mn_iic_cycle_time);
+	}
+
+	/* Reset TX fifo - must be after enable */
+	nthw_iic_reg_control_txfifo_reset(p);
+	nthw_iic_reg_tx_fifo_write(p, 0, 0, 0);
+
+	return 0;
+}
+
+void nthw_iic_delete(nthw_iic_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_iic_t));
+		free(p);
+	}
+}
+
+int nthw_iic_set_retry_params(nthw_iic_t *p, const int n_poll_delay, const int n_bus_ready_retry,
+	const int n_data_ready_retry, const int n_read_data_retry,
+	const int n_write_data_retry)
+{
+	p->mn_poll_delay = n_poll_delay >= 0 ? n_poll_delay : 10;
+
+	p->mn_bus_ready_retry = n_bus_ready_retry >= 0 ? n_bus_ready_retry : 1000;
+	p->mn_data_ready_retry = n_data_ready_retry >= 0 ? n_data_ready_retry : 1000;
+
+	p->mn_read_data_retry = n_read_data_retry >= 0 ? n_read_data_retry : 10;
+	p->mn_write_data_retry = n_write_data_retry >= 0 ? n_write_data_retry : 10;
+
+	return 0;
+}
+
+int nthw_iic_read_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	const int n_debug_mode = nthw_module_get_debug_mode(p->mp_mod_iic);
+
+	uint8_t *pb = (uint8_t *)p_void;
+	int retry = (p->mn_read_data_retry >= 0 ? p->mn_read_data_retry : 10);
+
+	if (n_debug_mode == 0xff) {
+		NT_LOG(DBG, NTHW, "%s: adr=0x%2.2x, reg=%d, len=%d\n", p_adapter_id_str, dev_addr,
+			a_reg_addr, data_len);
+	}
+
+	while (nthw_iic_readbyte(p, dev_addr, a_reg_addr, data_len, pb) != 0) {
+		retry--;
+
+		if (retry <= 0) {
+			NT_LOG(ERR, NTHW,
+				"%s: I2C%d: Read retry exhausted (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr);
+			return -1;
+
+		} else {
+			NT_LOG(DBG, NTHW, "%s: I2C%d: Read retry=%d (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr);
+		}
+	}
+
+	if (n_debug_mode == 0xff) {
+		NT_LOG(DBG, NTHW, "%s: adr=0x%2.2x, reg=%d, len=%d, retries remaining: %d\n",
+			p_adapter_id_str, dev_addr, a_reg_addr, data_len, retry);
+	}
+
+	return 0;
+}
+
+int nthw_iic_readbyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+
+	uint32_t value;
+	uint32_t i;
+
+	if (nthw_iic_bus_ready(p)) {
+		/* Reset TX fifo */
+		nthw_iic_reg_control_txfifo_reset(p);
+
+		/* Write device address to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_WR;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write a_reg_addr to TX FIFO */
+		nthw_iic_reg_tx_fifo_write(p, a_reg_addr, 0, 1);
+
+		if (!nthw_iic_bus_ready(p)) {
+			NT_LOG(ERR, NTHW, "%s: error: (%s:%u)\n", p_adapter_id_str, __func__,
+				__LINE__);
+			return -1;
+		}
+
+		/* Write device address + RD bit to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_RD;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write data_len to TX_FIFO and set stop bit!! */
+		nthw_iic_reg_tx_fifo_write(p, data_len, 0, 1);
+
+		for (i = 0; i < data_len; i++) {
+			/* Wait for RX FIFO not empty */
+			if (!nthw_iic_data_ready(p))
+				return -1;
+
+			/* Read data_len bytes from RX_FIFO */
+			nthw_iic_reg_read_i2c_rx_fifo(p, p_byte);
+			p_byte++;
+		}
+
+		return 0;
+
+	} else {
+		NT_LOG(ERR, NTHW, "%s: error: (%s:%u)\n", p_adapter_id_str, __func__, __LINE__);
+		return -1;
+	}
+
+	return 0;
+}
+
+int nthw_iic_write_data(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	void *p_void)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	int retry = (p->mn_write_data_retry >= 0 ? p->mn_write_data_retry : 10);
+	uint8_t *pb = (uint8_t *)p_void;
+
+	while (nthw_iic_writebyte(p, dev_addr, a_reg_addr, data_len, pb) != 0) {
+		retry--;
+
+		if (retry <= 0) {
+			NT_LOG(ERR, NTHW,
+				"%s: I2C%d: Write retry exhausted (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, dev_addr, a_reg_addr);
+			return -1;
+
+		} else {
+			NT_LOG(DBG, NTHW,
+				"%s: I2C%d: Write retry=%d (dev_addr=%d a_reg_addr=%d)\n",
+				p_adapter_id_str, p->mn_iic_instance, retry, dev_addr, a_reg_addr);
+		}
+	}
+
+	return 0;
+}
+
+int nthw_iic_writebyte(nthw_iic_t *p, uint8_t dev_addr, uint8_t a_reg_addr, uint8_t data_len,
+	uint8_t *p_byte)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	uint32_t value;
+	int count;
+	int i;
+
+	if (data_len == 0)
+		return -1;
+
+	count = data_len - 1;
+
+	if (nthw_iic_bus_ready(p)) {
+		/* Reset TX fifo */
+		nthw_iic_reg_control_txfifo_reset(p);
+
+		/* Write device address to TX_FIFO and set start bit!! */
+		value = (dev_addr << 1) | I2C_TRANSMIT_WR;
+		nthw_iic_reg_tx_fifo_write(p, value, 1, 0);
+
+		/* Write a_reg_addr to TX FIFO */
+		nthw_iic_reg_tx_fifo_write(p, a_reg_addr, 0, 0);
+
+		for (i = 0; i < count; i++) {
+			/* Write data byte to TX fifo and set stop bit */
+			nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 0);
+			p_byte++;
+		}
+
+		/* Write data byte to TX fifo and set stop bit */
+		nthw_iic_reg_tx_fifo_write(p, *p_byte, 0, 1);
+
+		if (!nthw_iic_bus_ready(p)) {
+			NT_LOG(WRN, NTHW, "%s: warn: !busReady (%s:%u)\n", p_adapter_id_str,
+				__func__, __LINE__);
+
+			while (true)
+				if (nthw_iic_bus_ready(p)) {
+					NT_LOG(DBG, NTHW, "%s: info: busReady (%s:%u)\n",
+						p_adapter_id_str, __func__, __LINE__);
+					break;
+				}
+		}
+
+		return 0;
+
+	} else {
+		NT_LOG(WRN, NTHW, "%s: (%s:%u)\n", p_adapter_id_str, __func__, __LINE__);
+		return -1;
+	}
+}
+
+/*
+ * Support function for read/write functions below. Waits for bus ready.
+ */
+bool nthw_iic_bus_ready(nthw_iic_t *p)
+{
+	int count = (p->mn_bus_ready_retry >= 0 ? p->mn_bus_ready_retry : 1000);
+	bool b_bus_busy = true;
+
+	while (true) {
+		nthw_iic_reg_busbusy(p, &b_bus_busy);
+
+		if (!b_bus_busy)
+			break;
+
+		count--;
+
+		if (count <= 0)	/* Test for timeout */
+			break;
+
+		if (p->mn_poll_delay != 0)
+			I2C_WAIT_US(p->mn_poll_delay);
+	}
+
+	if (count == 0)
+		return false;
+
+	return true;
+}
+
+/*
+ * Support function for read function. Waits for data ready.
+ */
+bool nthw_iic_data_ready(nthw_iic_t *p)
+{
+	int count = (p->mn_data_ready_retry >= 0 ? p->mn_data_ready_retry : 1000);
+	bool b_rx_fifo_empty = true;
+
+	while (true) {
+		nthw_iic_reg_rxfifo_empty(p, &b_rx_fifo_empty);
+
+		if (!b_rx_fifo_empty)
+			break;
+
+		count--;
+
+		if (count <= 0)	/* Test for timeout */
+			break;
+
+		if (p->mn_poll_delay != 0)
+			I2C_WAIT_US(p->mn_poll_delay);
+	}
+
+	if (count == 0)
+		return false;
+
+	return true;
+}
+
+int nthw_iic_scan_dev_addr(nthw_iic_t *p, int n_dev_addr, int n_reg_addr)
+{
+	const char *const p_adapter_id_str = p->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	(void)p_adapter_id_str;
+	int res;
+	uint8_t data_val = -1;
+	res = nthw_iic_readbyte(p, (uint8_t)n_dev_addr, (uint8_t)n_reg_addr, 1, &data_val);
+
+	if (res == 0) {
+		NT_LOG(DBG, NTHW,
+			"%s: I2C%d: devaddr=0x%02X (%03d) regaddr=%02X val=%02X (%03d) res=%d\n",
+			p_adapter_id_str, p->mn_iic_instance, n_dev_addr, n_dev_addr, n_reg_addr,
+			data_val, data_val, res);
+	}
+
+	return res;
+}
+
+int nthw_iic_scan(nthw_iic_t *p)
+{
+	int i;
+
+	for (i = 0; i < 128; i++)
+		(void)nthw_iic_scan_dev_addr(p, i, 0x00);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c
new file mode 100644
index 0000000000..abffd34fc3
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_mac_pcs_xxv.c
@@ -0,0 +1,1169 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_mac_pcs_xxv.h"
+
+static void nthw_mac_pcs_xxv_field_set_or_clr_flush(const nthw_field_t *f, bool set)
+{
+	if (f) {
+		nthw_field_get_updated(f);
+
+		if (set)
+			nthw_field_set_flush(f);
+
+		else
+			nthw_field_clr_flush(f);
+	}
+}
+
+nthw_mac_pcs_xxv_t *nthw_mac_pcs_xxv_new(void)
+{
+	nthw_mac_pcs_xxv_t *p = malloc(sizeof(nthw_mac_pcs_xxv_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_mac_pcs_xxv_t));
+
+	return p;
+}
+
+void nthw_mac_pcs_xxv_delete(nthw_mac_pcs_xxv_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_mac_pcs_xxv_t));
+		free(p);
+	}
+}
+
+void nthw_mac_pcs_xxv_get_link_summary(nthw_mac_pcs_xxv_t *p,
+	uint32_t *p_abs,
+	uint32_t *p_nt_phy_link_state,
+	uint32_t *p_lh_abs,
+	uint32_t *p_ll_nt_phy_link_state,
+	uint32_t *p_link_down_cnt,
+	uint32_t *p_nim_interr,
+	uint32_t *p_lh_local_fault,
+	uint32_t *p_lh_remote_fault,
+	uint32_t *p_lh_internal_local_fault,
+	uint32_t *p_lh_received_local_fault,
+	uint8_t index)
+{
+	struct nthw_mac_pcs_xxv_registers_fields *r = &p->regs[index];	/* register and fields */
+
+	assert(p);
+
+	nthw_register_update(r->mp_reg_link_summary);
+
+	if (p_abs)
+		*p_abs = nthw_field_get_val32(r->mp_fld_link_summary_abs);
+
+	if (p_nt_phy_link_state) {
+		*p_nt_phy_link_state =
+			nthw_field_get_val32(r->mp_fld_link_summary_nt_phy_link_state);
+	}
+
+	if (p_lh_abs)
+		*p_lh_abs = nthw_field_get_val32(r->mp_fld_link_summary_lh_abs);
+
+	if (p_ll_nt_phy_link_state) {
+		*p_ll_nt_phy_link_state =
+			nthw_field_get_val32(r->mp_fld_link_summary_ll_nt_phy_link_state);
+	}
+
+	if (p_link_down_cnt)
+		*p_link_down_cnt = nthw_field_get_val32(r->mp_fld_link_summary_link_down_cnt);
+
+	if (p_nim_interr)
+		*p_nim_interr = nthw_field_get_val32(r->mp_fld_link_summary_nim_interr);
+
+	if (p_lh_local_fault)
+		*p_lh_local_fault = nthw_field_get_val32(r->mp_fld_link_summary_lh_local_fault);
+
+	if (p_lh_remote_fault)
+		*p_lh_remote_fault = nthw_field_get_val32(r->mp_fld_link_summary_lh_remote_fault);
+
+	if (p_lh_internal_local_fault) {
+		*p_lh_internal_local_fault =
+			nthw_field_get_val32(r->mp_fld_link_summary_lh_internal_local_fault);
+	}
+
+	if (p_lh_received_local_fault) {
+		*p_lh_received_local_fault =
+			nthw_field_get_val32(r->mp_fld_link_summary_lh_received_local_fault);
+	}
+}
+
+void nthw_mac_pcs_xxv_reset_rx_gt_data(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index)
+{
+	const nthw_field_t *const f = p->regs[index].mp_fld_sub_rst_rx_gt_data;
+
+	nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable);
+}
+
+/*
+ * QPLL lock signal.
+ * For cores capable of 10G only, there are only 1 QPLL. For cores capable of
+ * 10G/25G, there are 2 QPLLs.
+ */
+void nthw_mac_pcs_xxv_set_rx_mac_pcs_rst(nthw_mac_pcs_xxv_t *p, bool enable, uint8_t index)
+{
+	const nthw_field_t *const f = p->regs[index].mp_fld_sub_rst_rx_mac_pcs;
+
+	nthw_mac_pcs_xxv_field_set_or_clr_flush(f, enable);
+}
+
+int nthw_mac_pcs_xxv_init(nthw_mac_pcs_xxv_t *p, nthw_fpga_t *p_fpga, int n_instance,
+	int n_channels, bool mac_8x10G)
+{
+	nthw_module_t *p_mod = nthw_fpga_query_module(p_fpga, MOD_MAC_PCS_XXV, n_instance);
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *module = p_mod;
+	uint64_t n_module_version_packed64 = -1;
+	nthw_register_t *r;
+	nthw_register_t *(*get_register)(nthw_module_t *, nthw_id_t) = nthw_module_get_register;
+	nthw_field_t *(*get_field)(const nthw_register_t *, nthw_id_t) = nthw_register_get_field;
+	nthw_field_t *(*query_field)(const nthw_register_t *, nthw_id_t) =
+		nthw_register_query_field;
+	struct nthw_mac_pcs_xxv_registers_fields *rf;
+
+	if (p == NULL)
+		return p_mod == NULL ? -1 : 0;
+
+	if (p_mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: MAC_PCS_XXV instance=%d: no such instance\n",
+			p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_mac_pcs_xxv = p_mod;
+	p->m_mac_8x10G = mac_8x10G;
+
+	memset(p->regs, 0, sizeof(p->regs));
+
+	n_module_version_packed64 = nthw_module_get_version_packed64(p->mp_mod_mac_pcs_xxv);
+
+	switch (n_module_version_packed64) {
+	case (0UL << 32) | 0UL:	/* 0.0 */
+	case (0UL << 32) | 1UL:	/* 0.1 */
+	case (0UL << 32) | 2UL:	/* 0.2 */
+	case (0UL << 32) | 3UL:	/* 0.3 */
+		NT_LOG(DBG, NTHW, "%s: MAC_PCS_XXV instance=%d: version=0x%08lX\n",
+			p_adapter_id_str, p->mn_instance, n_module_version_packed64);
+		break;
+
+	default:
+		NT_LOG(ERR, NTHW,
+			"%s: MAC_PCS_XXV instance=%d: version=0x%08lX: unsupported module version\n",
+			p_adapter_id_str, p->mn_instance, n_module_version_packed64);
+		return -1;
+	}
+
+	assert(n_channels == 1 || n_channels == 2 || n_channels == 4);
+
+	/* Register MAC_PCS_XXV_CORE_CONF_0 -- MAC_PCS_XXV_CORE_CONF_3 */
+	if (n_channels <= 4) {
+		/* Initialize regs/fields for sub-module/channel 0 */
+		rf = &p->regs[0];
+		r = get_register(module, MAC_PCS_XXV_CORE_CONF_0);
+
+		rf->mp_reg_core_conf = r;
+		rf->mp_fld_core_conf_rx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_0_RX_ENABLE);
+		rf->mp_fld_core_conf_rx_force_resync =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_RX_FORCE_RESYNC);
+		rf->mp_fld_core_conf_tx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_ENABLE);
+		rf->mp_fld_core_conf_tx_ins_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_INS_FCS);
+		rf->mp_fld_core_conf_tx_ign_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_IGN_FCS);
+		rf->mp_fld_core_conf_tx_send_lfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_LFI);
+		rf->mp_fld_core_conf_tx_send_rfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_RFI);
+		rf->mp_fld_core_conf_tx_send_idle =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_TX_SEND_IDLE);
+		rf->mp_fld_core_conf_inline_mode =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_INLINE_MODE);
+		rf->mp_fld_core_conf_line_loopback =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_0_LINE_LOOPBACK);
+		rf->mp_fld_core_conf_ts_at_eop = get_field(r, MAC_PCS_XXV_CORE_CONF_0_TS_AT_EOP);
+	}
+
+	if (n_channels >= 2) {
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+		r = get_register(module, MAC_PCS_XXV_CORE_CONF_1);
+
+		rf->mp_reg_core_conf = r;
+		rf->mp_fld_core_conf_rx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_1_RX_ENABLE);
+		rf->mp_fld_core_conf_rx_force_resync =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_RX_FORCE_RESYNC);
+		rf->mp_fld_core_conf_tx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_ENABLE);
+		rf->mp_fld_core_conf_tx_ins_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_INS_FCS);
+		rf->mp_fld_core_conf_tx_ign_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_IGN_FCS);
+		rf->mp_fld_core_conf_tx_send_lfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_LFI);
+		rf->mp_fld_core_conf_tx_send_rfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_RFI);
+		rf->mp_fld_core_conf_tx_send_idle =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_TX_SEND_IDLE);
+		rf->mp_fld_core_conf_inline_mode =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_INLINE_MODE);
+		rf->mp_fld_core_conf_line_loopback =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_1_LINE_LOOPBACK);
+		rf->mp_fld_core_conf_ts_at_eop = get_field(r, MAC_PCS_XXV_CORE_CONF_1_TS_AT_EOP);
+	}
+
+	if (n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+		r = get_register(module, MAC_PCS_XXV_CORE_CONF_2);
+
+		rf->mp_reg_core_conf = r;
+		rf->mp_fld_core_conf_rx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_2_RX_ENABLE);
+		rf->mp_fld_core_conf_rx_force_resync =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_RX_FORCE_RESYNC);
+		rf->mp_fld_core_conf_tx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_ENABLE);
+		rf->mp_fld_core_conf_tx_ins_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_INS_FCS);
+		rf->mp_fld_core_conf_tx_ign_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_IGN_FCS);
+		rf->mp_fld_core_conf_tx_send_lfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_LFI);
+		rf->mp_fld_core_conf_tx_send_rfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_RFI);
+		rf->mp_fld_core_conf_tx_send_idle =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_TX_SEND_IDLE);
+		rf->mp_fld_core_conf_inline_mode =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_INLINE_MODE);
+		rf->mp_fld_core_conf_line_loopback =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_2_LINE_LOOPBACK);
+		rf->mp_fld_core_conf_ts_at_eop = get_field(r, MAC_PCS_XXV_CORE_CONF_2_TS_AT_EOP);
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+		r = get_register(module, MAC_PCS_XXV_CORE_CONF_3);
+
+		rf->mp_reg_core_conf = r;
+		rf->mp_fld_core_conf_rx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_3_RX_ENABLE);
+		rf->mp_fld_core_conf_rx_force_resync =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_RX_FORCE_RESYNC);
+		rf->mp_fld_core_conf_tx_enable = get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_ENABLE);
+		rf->mp_fld_core_conf_tx_ins_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_INS_FCS);
+		rf->mp_fld_core_conf_tx_ign_fcs = get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_IGN_FCS);
+		rf->mp_fld_core_conf_tx_send_lfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_LFI);
+		rf->mp_fld_core_conf_tx_send_rfi =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_RFI);
+		rf->mp_fld_core_conf_tx_send_idle =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_TX_SEND_IDLE);
+		rf->mp_fld_core_conf_inline_mode =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_INLINE_MODE);
+		rf->mp_fld_core_conf_line_loopback =
+			get_field(r, MAC_PCS_XXV_CORE_CONF_3_LINE_LOOPBACK);
+		rf->mp_fld_core_conf_ts_at_eop = get_field(r, MAC_PCS_XXV_CORE_CONF_3_TS_AT_EOP);
+	}
+
+	/*
+	 * Registers MAC_PCS_XXV_ANEG_CONFIG_0 -- MAC_PCS_XXV_ANEG_CONFIG_3
+	 * and       MAC_PCS_XXV_ANEG_ABILITY_0 -- MAC_PCS_XXV_ANEG_ABILITY_3
+	 * and       MAC_PCS_XXV_LT_CONF_0 -- MAC_PCS_XXV_LT_CONF_3
+	 */
+	if (!mac_8x10G && n_channels <= 4) {
+		/*
+		 * 2 x 10 25 G
+		 * ANEG_CONFIG
+		 */
+		rf = &p->regs[0];
+
+		r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_0);
+		rf->mp_reg_aneg_config = r;
+		rf->mp_fld_aneg_config_enable = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_ENABLE);
+		rf->mp_fld_aneg_config_bypass = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_BYPASS);
+		rf->mp_fld_aneg_config_restart = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_RESTART);
+		rf->mp_fld_aneg_config_pseudo = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_PSEUDO);
+		rf->mp_fld_aneg_config_nonce_seed =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_NONCE_SEED);
+		rf->mp_fld_aneg_config_remote_fault =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_REMOTE_FAULT);
+		rf->mp_fld_aneg_config_pause = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_PAUSE);
+		rf->mp_fld_aneg_config_asmdir = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_ASMDIR);
+		rf->mp_fld_aneg_config_fec74_request10g =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC74_REQUEST_10G);
+		rf->mp_fld_aneg_config_hide_fec74 =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_HIDE_FEC74);
+		rf->mp_fld_aneg_config_fec74_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC74_REQUEST);
+		rf->mp_fld_aneg_config_fec91_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC91_REQUEST);
+		rf->mp_fld_aneg_config_fec91_ability =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_FEC91_ABILITY);
+		rf->mp_fld_aneg_config_rs_fec_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_RS_FEC_REQUEST);
+		rf->mp_fld_aneg_config_sw_fec_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_SW_FEC_OVERWRITE);
+		rf->mp_fld_aneg_config_sw_speed_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_0_SW_SPEED_OVERWRITE);
+
+		/* ANEG_ABILITY */
+		r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_0);
+		rf->mp_reg_aneg_ability = r;
+
+		rf->mp_fld_aneg_ability_25g_base_cr =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_cr) {
+			rf->mp_fld_aneg_ability_25g_base_cr =
+				query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR);
+		}
+
+		rf->mp_fld_aneg_ability_25g_base_crs =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR_S);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_crs) {
+			rf->mp_fld_aneg_ability_25g_base_crs =
+				query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR_S);
+		}
+
+		rf->mp_fld_aneg_ability_25g_base_cr1 =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_BASE25G_CR1);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_cr1) {
+			rf->mp_fld_aneg_ability_25g_base_cr1 =
+				query_field(r, MAC_PCS_XXV_ANEG_ABILITY_0_25GBASE_CR1);
+		}
+
+		/* LT_CONF */
+		r = get_register(module, MAC_PCS_XXV_LT_CONF_0);
+		rf->mp_reg_lt_conf = r;
+		rf->mp_fld_lt_conf_enable = get_field(r, MAC_PCS_XXV_LT_CONF_0_ENABLE);
+		rf->mp_fld_lt_conf_restart = get_field(r, MAC_PCS_XXV_LT_CONF_0_RESTART);
+		rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_0_SEED);
+	}
+
+	if (!mac_8x10G && n_channels >= 2) {
+		/*
+		 * 2 x 10 25 G
+		 * ANEG_CONFIG
+		 */
+
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+
+		r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_1);
+		rf->mp_reg_aneg_config = r;
+		rf->mp_fld_aneg_config_enable = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_ENABLE);
+		rf->mp_fld_aneg_config_bypass = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_BYPASS);
+		rf->mp_fld_aneg_config_restart = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_RESTART);
+		rf->mp_fld_aneg_config_pseudo = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_PSEUDO);
+		rf->mp_fld_aneg_config_nonce_seed =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_NONCE_SEED);
+		rf->mp_fld_aneg_config_remote_fault =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_REMOTE_FAULT);
+		rf->mp_fld_aneg_config_pause = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_PAUSE);
+		rf->mp_fld_aneg_config_asmdir = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_ASMDIR);
+		rf->mp_fld_aneg_config_fec74_request10g =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC74_REQUEST_10G);
+		rf->mp_fld_aneg_config_hide_fec74 =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_HIDE_FEC74);
+		rf->mp_fld_aneg_config_fec74_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC74_REQUEST);
+		rf->mp_fld_aneg_config_fec91_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC91_REQUEST);
+		rf->mp_fld_aneg_config_fec91_ability =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_FEC91_ABILITY);
+		rf->mp_fld_aneg_config_rs_fec_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_RS_FEC_REQUEST);
+		rf->mp_fld_aneg_config_sw_fec_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_SW_FEC_OVERWRITE);
+		rf->mp_fld_aneg_config_sw_speed_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_1_SW_SPEED_OVERWRITE);
+
+		/* ANEG_ABILITY */
+		r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_1);
+		rf->mp_reg_aneg_ability = r;
+
+		rf->mp_fld_aneg_ability_25g_base_cr =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_cr) {
+			rf->mp_fld_aneg_ability_25g_base_cr =
+				get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR);
+		}
+
+		rf->mp_fld_aneg_ability_25g_base_crs =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR_S);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_crs) {
+			rf->mp_fld_aneg_ability_25g_base_crs =
+				get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR_S);
+		}
+
+		rf->mp_fld_aneg_ability_25g_base_cr1 =
+			query_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_BASE25G_CR1);
+
+		if (!rf->mp_fld_aneg_ability_25g_base_cr1) {
+			rf->mp_fld_aneg_ability_25g_base_cr1 =
+				get_field(r, MAC_PCS_XXV_ANEG_ABILITY_1_25GBASE_CR1);
+		}
+
+		/* LT_CONF */
+		r = get_register(module, MAC_PCS_XXV_LT_CONF_1);
+		rf->mp_reg_lt_conf = r;
+		rf->mp_fld_lt_conf_enable = get_field(r, MAC_PCS_XXV_LT_CONF_1_ENABLE);
+		rf->mp_fld_lt_conf_restart = get_field(r, MAC_PCS_XXV_LT_CONF_1_RESTART);
+		rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_1_SEED);
+	}
+
+	if (!mac_8x10G && n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+
+		r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_2);
+		rf->mp_reg_aneg_config = r;
+		rf->mp_fld_aneg_config_enable = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_ENABLE);
+		rf->mp_fld_aneg_config_bypass = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_BYPASS);
+		rf->mp_fld_aneg_config_restart = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_RESTART);
+		rf->mp_fld_aneg_config_pseudo = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_PSEUDO);
+		rf->mp_fld_aneg_config_nonce_seed =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_NONCE_SEED);
+		rf->mp_fld_aneg_config_remote_fault =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_REMOTE_FAULT);
+		rf->mp_fld_aneg_config_pause = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_PAUSE);
+		rf->mp_fld_aneg_config_asmdir = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_ASMDIR);
+		rf->mp_fld_aneg_config_fec74_request10g =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC74_REQUEST_10G);
+		rf->mp_fld_aneg_config_hide_fec74 =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_HIDE_FEC74);
+		rf->mp_fld_aneg_config_fec74_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC74_REQUEST);
+		rf->mp_fld_aneg_config_fec91_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC91_REQUEST);
+		rf->mp_fld_aneg_config_fec91_ability =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_FEC91_ABILITY);
+		rf->mp_fld_aneg_config_rs_fec_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_RS_FEC_REQUEST);
+		rf->mp_fld_aneg_config_sw_fec_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_SW_FEC_OVERWRITE);
+		rf->mp_fld_aneg_config_sw_speed_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_2_SW_SPEED_OVERWRITE);
+
+		/* ANEG_ABILITY */
+		r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_2);
+		rf->mp_reg_aneg_ability = r;
+		rf->mp_fld_aneg_ability_25g_base_cr =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR);
+		rf->mp_fld_aneg_ability_25g_base_crs =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR_S);
+		rf->mp_fld_aneg_ability_25g_base_cr1 =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_2_25GBASE_CR1);
+
+		/* LT_CONF */
+		r = get_register(module, MAC_PCS_XXV_LT_CONF_2);
+		rf->mp_reg_lt_conf = r;
+		rf->mp_fld_lt_conf_enable = get_field(r, MAC_PCS_XXV_LT_CONF_2_ENABLE);
+		rf->mp_fld_lt_conf_restart = get_field(r, MAC_PCS_XXV_LT_CONF_2_RESTART);
+		rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_2_SEED);
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+
+		r = get_register(module, MAC_PCS_XXV_ANEG_CONFIG_3);
+		rf->mp_reg_aneg_config = r;
+		rf->mp_fld_aneg_config_enable = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_ENABLE);
+		rf->mp_fld_aneg_config_bypass = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_BYPASS);
+		rf->mp_fld_aneg_config_restart = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_RESTART);
+		rf->mp_fld_aneg_config_pseudo = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_PSEUDO);
+		rf->mp_fld_aneg_config_nonce_seed =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_NONCE_SEED);
+		rf->mp_fld_aneg_config_remote_fault =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_REMOTE_FAULT);
+		rf->mp_fld_aneg_config_pause = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_PAUSE);
+		rf->mp_fld_aneg_config_asmdir = get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_ASMDIR);
+		rf->mp_fld_aneg_config_fec74_request10g =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC74_REQUEST_10G);
+		rf->mp_fld_aneg_config_hide_fec74 =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_HIDE_FEC74);
+		rf->mp_fld_aneg_config_fec74_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC74_REQUEST);
+		rf->mp_fld_aneg_config_fec91_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC91_REQUEST);
+		rf->mp_fld_aneg_config_fec91_ability =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_FEC91_ABILITY);
+		rf->mp_fld_aneg_config_rs_fec_request =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_RS_FEC_REQUEST);
+		rf->mp_fld_aneg_config_sw_fec_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_SW_FEC_OVERWRITE);
+		rf->mp_fld_aneg_config_sw_speed_overwrite =
+			get_field(r, MAC_PCS_XXV_ANEG_CONFIG_3_SW_SPEED_OVERWRITE);
+
+		/* ANEG_ABILITY */
+		r = get_register(module, MAC_PCS_XXV_ANEG_ABILITY_3);
+		rf->mp_reg_aneg_ability = r;
+		rf->mp_fld_aneg_ability_25g_base_cr =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR);
+		rf->mp_fld_aneg_ability_25g_base_crs =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR_S);
+		rf->mp_fld_aneg_ability_25g_base_cr1 =
+			get_field(r, MAC_PCS_XXV_ANEG_ABILITY_3_25GBASE_CR1);
+
+		/* LT_CONF */
+		r = get_register(module, MAC_PCS_XXV_LT_CONF_3);
+		rf->mp_reg_lt_conf = r;
+		rf->mp_fld_lt_conf_enable = get_field(r, MAC_PCS_XXV_LT_CONF_3_ENABLE);
+		rf->mp_fld_lt_conf_restart = get_field(r, MAC_PCS_XXV_LT_CONF_3_RESTART);
+		rf->mp_fld_lt_conf_seed = get_field(r, MAC_PCS_XXV_LT_CONF_3_SEED);
+	}
+
+	/*
+	 * Registers MAC_PCS_XXV_SUB_RST_0 -- MAC_PCS_XXV_SUB_RST_3
+	 * and       MAC_PCS_XXV_SUB_RST_STATUS_0 -- MAC_PCS_XXV_SUB_RST_STATUS_3
+	 */
+	if (n_channels <= 4) {
+		/* Initialize regs/fields for sub-module/channel 0 */
+		rf = &p->regs[0];
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_0);
+
+		rf->mp_reg_sub_rst = r;
+		rf->mp_fld_sub_rst_rx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_MAC_PCS);
+		rf->mp_fld_sub_rst_tx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_MAC_PCS);
+		rf->mp_fld_sub_rst_rx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_GT_DATA);
+		rf->mp_fld_sub_rst_tx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_GT_DATA);
+		rf->mp_fld_sub_rst_rx_buf = get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_BUF);
+		rf->mp_fld_sub_rst_rx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_PMA);
+		rf->mp_fld_sub_rst_tx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_PMA);
+		rf->mp_fld_sub_rst_rx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_0_RX_PCS);
+		rf->mp_fld_sub_rst_tx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_0_TX_PCS);
+		rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_0_AN_LT);
+		rf->mp_fld_sub_rst_speed_ctrl = query_field(r, MAC_PCS_XXV_SUB_RST_0_SPEED_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_0);
+		rf->mp_reg_sub_rst_status = r;
+		rf->mp_fld_sub_rst_status_user_rx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_USER_RX_RST);
+		rf->mp_fld_sub_rst_status_user_tx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_USER_TX_RST);
+		rf->mp_fld_sub_rst_status_qpll_lock =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_0_QPLL_LOCK);
+	}
+
+	if (n_channels >= 2) {
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_1);
+
+		rf->mp_reg_sub_rst = r;
+		rf->mp_fld_sub_rst_rx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_MAC_PCS);
+		rf->mp_fld_sub_rst_tx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_MAC_PCS);
+		rf->mp_fld_sub_rst_rx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_GT_DATA);
+		rf->mp_fld_sub_rst_tx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_GT_DATA);
+		rf->mp_fld_sub_rst_rx_buf = get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_BUF);
+		rf->mp_fld_sub_rst_rx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_PMA);
+		rf->mp_fld_sub_rst_tx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_PMA);
+		rf->mp_fld_sub_rst_rx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_1_RX_PCS);
+		rf->mp_fld_sub_rst_tx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_1_TX_PCS);
+		rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_1_AN_LT);
+		rf->mp_fld_sub_rst_speed_ctrl = query_field(r, MAC_PCS_XXV_SUB_RST_1_SPEED_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_1);
+		rf->mp_reg_sub_rst_status = r;
+		rf->mp_fld_sub_rst_status_user_rx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_USER_RX_RST);
+		rf->mp_fld_sub_rst_status_user_tx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_USER_TX_RST);
+		rf->mp_fld_sub_rst_status_qpll_lock =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_1_QPLL_LOCK);
+	}
+
+	if (n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_2);
+
+		rf->mp_reg_sub_rst = r;
+		rf->mp_fld_sub_rst_rx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_MAC_PCS);
+		rf->mp_fld_sub_rst_tx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_MAC_PCS);
+		rf->mp_fld_sub_rst_rx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_GT_DATA);
+		rf->mp_fld_sub_rst_tx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_GT_DATA);
+		rf->mp_fld_sub_rst_rx_buf = get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_BUF);
+		rf->mp_fld_sub_rst_rx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_PMA);
+		rf->mp_fld_sub_rst_tx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_PMA);
+		rf->mp_fld_sub_rst_rx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_2_RX_PCS);
+		rf->mp_fld_sub_rst_tx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_2_TX_PCS);
+		rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_2_AN_LT);
+		rf->mp_fld_sub_rst_speed_ctrl = query_field(r, MAC_PCS_XXV_SUB_RST_2_SPEED_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_2);
+		rf->mp_reg_sub_rst_status = r;
+		rf->mp_fld_sub_rst_status_user_rx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_USER_RX_RST);
+		rf->mp_fld_sub_rst_status_user_tx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_USER_TX_RST);
+		rf->mp_fld_sub_rst_status_qpll_lock =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_2_QPLL_LOCK);
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_3);
+
+		rf->mp_reg_sub_rst = r;
+		rf->mp_fld_sub_rst_rx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_MAC_PCS);
+		rf->mp_fld_sub_rst_tx_mac_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_MAC_PCS);
+		rf->mp_fld_sub_rst_rx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_GT_DATA);
+		rf->mp_fld_sub_rst_tx_gt_data = get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_GT_DATA);
+		rf->mp_fld_sub_rst_rx_buf = get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_BUF);
+		rf->mp_fld_sub_rst_rx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_PMA);
+		rf->mp_fld_sub_rst_tx_pma = get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_PMA);
+		rf->mp_fld_sub_rst_rx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_3_RX_PCS);
+		rf->mp_fld_sub_rst_tx_pcs = get_field(r, MAC_PCS_XXV_SUB_RST_3_TX_PCS);
+		rf->mp_fld_sub_rst_an_lt = get_field(r, MAC_PCS_XXV_SUB_RST_3_AN_LT);
+		rf->mp_fld_sub_rst_speed_ctrl = query_field(r, MAC_PCS_XXV_SUB_RST_3_SPEED_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_SUB_RST_STATUS_3);
+		rf->mp_reg_sub_rst_status = r;
+		rf->mp_fld_sub_rst_status_user_rx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_USER_RX_RST);
+		rf->mp_fld_sub_rst_status_user_tx_rst =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_USER_TX_RST);
+		rf->mp_fld_sub_rst_status_qpll_lock =
+			get_field(r, MAC_PCS_XXV_SUB_RST_STATUS_3_QPLL_LOCK);
+	}
+
+	/* Registers MAC_PCS_XXV_LINK_SUMMARY_0 -- MAC_PCS_XXV_LINK_SUMMARY_3 */
+	if (n_channels <= 4) {
+		/* Initialize regs/fields for sub-module/channel 0 */
+		rf = &p->regs[0];
+		r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_0);
+
+		rf->mp_reg_link_summary = r;
+		rf->mp_fld_link_summary_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_NT_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_ll_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_ABS);
+		rf->mp_fld_link_summary_lh_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_ABS);
+		rf->mp_fld_link_summary_link_down_cnt =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LINK_DOWN_CNT);
+
+		if (!mac_8x10G) {
+			rf->mp_fld_link_summary_ll_rx_fec74_lock =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_FEC74_LOCK);
+			rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_RSFEC_HI_SER);
+			rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_0_LL_TX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_PCS_VALID_CTRL_CODE);
+		}
+
+		rf->mp_fld_link_summary_ll_rx_block_lock =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LL_RX_BLOCK_LOCK);
+		rf->mp_fld_link_summary_lh_rx_high_bit_error_rate =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RX_HIGH_BIT_ERROR_RATE);
+		rf->mp_fld_link_summary_lh_internal_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_INTERNAL_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_received_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_RECEIVED_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_remote_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_LH_REMOTE_FAULT);
+		rf->mp_fld_link_summary_nim_interr =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_0_NIM_INTERR);
+	}
+
+	if (n_channels >= 2) {
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+		r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_1);
+
+		rf->mp_reg_link_summary = r;
+		rf->mp_fld_link_summary_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_NT_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_ll_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_ABS);
+		rf->mp_fld_link_summary_lh_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_ABS);
+		rf->mp_fld_link_summary_link_down_cnt =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LINK_DOWN_CNT);
+
+		if (!mac_8x10G) {
+			rf->mp_fld_link_summary_ll_rx_fec74_lock =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_FEC74_LOCK);
+			rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_RSFEC_HI_SER);
+			rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_1_LL_TX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_PCS_VALID_CTRL_CODE);
+		}
+
+		rf->mp_fld_link_summary_ll_rx_block_lock =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LL_RX_BLOCK_LOCK);
+		rf->mp_fld_link_summary_lh_rx_high_bit_error_rate =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RX_HIGH_BIT_ERROR_RATE);
+		rf->mp_fld_link_summary_lh_internal_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_INTERNAL_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_received_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_RECEIVED_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_remote_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_LH_REMOTE_FAULT);
+		rf->mp_fld_link_summary_nim_interr =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_1_NIM_INTERR);
+	}
+
+	if (n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+		r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_2);
+
+		rf->mp_reg_link_summary = r;
+		rf->mp_fld_link_summary_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_NT_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_ll_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_ABS);
+		rf->mp_fld_link_summary_lh_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_ABS);
+		rf->mp_fld_link_summary_link_down_cnt =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LINK_DOWN_CNT);
+
+		if (!mac_8x10G) {
+			rf->mp_fld_link_summary_ll_rx_fec74_lock =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_FEC74_LOCK);
+			rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_RSFEC_HI_SER);
+			rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_2_LL_TX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_PCS_VALID_CTRL_CODE);
+		}
+
+		rf->mp_fld_link_summary_ll_rx_block_lock =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LL_RX_BLOCK_LOCK);
+		rf->mp_fld_link_summary_lh_rx_high_bit_error_rate =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RX_HIGH_BIT_ERROR_RATE);
+		rf->mp_fld_link_summary_lh_internal_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_INTERNAL_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_received_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_RECEIVED_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_remote_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_LH_REMOTE_FAULT);
+		rf->mp_fld_link_summary_nim_interr =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_2_NIM_INTERR);
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+		r = get_register(module, MAC_PCS_XXV_LINK_SUMMARY_3);
+
+		rf->mp_reg_link_summary = r;
+		rf->mp_fld_link_summary_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_NT_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_ll_nt_phy_link_state =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_PHY_LINK_STATE);
+		rf->mp_fld_link_summary_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_ABS);
+		rf->mp_fld_link_summary_lh_abs = get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_ABS);
+		rf->mp_fld_link_summary_link_down_cnt =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LINK_DOWN_CNT);
+
+		if (!mac_8x10G) {
+			rf->mp_fld_link_summary_ll_rx_fec74_lock =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_FEC74_LOCK);
+			rf->mp_fld_link_summary_lh_rx_rsfec_hi_ser =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_RSFEC_HI_SER);
+			rf->mp_fld_link_summary_ll_rx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_ll_tx_rsfec_lane_alignment =
+				get_field(r,
+					MAC_PCS_XXV_LINK_SUMMARY_3_LL_TX_RSFEC_LANE_ALIGNMENT);
+			rf->mp_fld_link_summary_lh_rx_pcs_valid_ctrl_code =
+				get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_PCS_VALID_CTRL_CODE);
+		}
+
+		rf->mp_fld_link_summary_ll_rx_block_lock =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LL_RX_BLOCK_LOCK);
+		rf->mp_fld_link_summary_lh_rx_high_bit_error_rate =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RX_HIGH_BIT_ERROR_RATE);
+		rf->mp_fld_link_summary_lh_internal_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_INTERNAL_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_received_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_RECEIVED_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_local_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_LOCAL_FAULT);
+		rf->mp_fld_link_summary_lh_remote_fault =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_LH_REMOTE_FAULT);
+		rf->mp_fld_link_summary_nim_interr =
+			get_field(r, MAC_PCS_XXV_LINK_SUMMARY_3_NIM_INTERR);
+	}
+
+	/*
+	 * Registers MAC_PCS_XXV_GTY_LOOP_0 -- MAC_PCS_XXV_GTY_LOOP_3
+	 * and       MAC_PCS_XXV_GTY_CTL_RX_0 -- MAC_PCS_XXV_GTY_CTL_RX_3
+	 * and       MAC_PCS_XXV_GTY_CTL_TX_0 -- MAC_PCS_XXV_GTY_CTL_TX_3
+	 * and       MAC_PCS_XXV_LINK_SPEED_0 -- MAC_PCS_XXV_LINK_SPEED_3
+	 * and       MAC_PCS_XXV_RS_FEC_CONF_0 -- MAC_PCS_XXV_RS_FEC_CONF_0
+	 */
+	if (n_channels <= 4) {
+		/* Initialize regs/fields for sub-module/channel 0 */
+		rf = &p->regs[0];
+
+		r = get_register(module, MAC_PCS_XXV_GTY_LOOP_0);
+		rf->mp_reg_gty_loop = r;
+		rf->mp_fld_gty_loop_gt_loop = get_field(r, MAC_PCS_XXV_GTY_LOOP_0_GT_LOOP);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_0);
+		rf->mp_reg_gty_ctl_rx = r;
+		rf->mp_fld_gty_ctl_rx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_POLARITY);
+		rf->mp_fld_gty_ctl_rx_lpm_en = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_LPM_EN);
+		rf->mp_fld_gty_ctl_rx_equa_rst = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_0_EQUA_RST);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_0);
+		rf->mp_fld_gty_ctl_tx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_0_POLARITY);
+		rf->mp_fld_gty_ctl_tx_inhibit = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_0_INHIBIT);
+
+		if (!mac_8x10G) {
+			r = get_register(module, MAC_PCS_XXV_LINK_SPEED_0);
+			rf->mp_reg_link_speed = get_register(module, MAC_PCS_XXV_LINK_SPEED_0);
+
+			rf->mp_fld_link_speed_10g = query_field(r, MAC_PCS_XXV_LINK_SPEED_0_SPEED);
+
+			if (!rf->mp_fld_link_speed_10g) {
+				rf->mp_fld_link_speed_10g =
+					get_field(r, MAC_PCS_XXV_LINK_SPEED_0_10G);
+			}
+
+			rf->mp_fld_link_speed_toggle =
+				get_field(r, MAC_PCS_XXV_LINK_SPEED_0_TOGGLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_0);
+			rf->mp_reg_rs_fec_conf = r;
+			rf->mp_fld_rs_fec_conf_rs_fec_enable =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CONF_0_RS_FEC_ENABLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_0);
+			rf->mp_reg_rs_fec_ccw = r;
+			rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_0_RS_FEC_CCW_CNT);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_0);
+			rf->mp_reg_rs_fec_ucw = r;
+			rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_0_RS_FEC_UCW_CNT);
+		}
+	}
+
+	if (n_channels >= 2) {
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+
+		r = get_register(module, MAC_PCS_XXV_GTY_LOOP_1);
+		rf->mp_reg_gty_loop = r;
+		rf->mp_fld_gty_loop_gt_loop = get_field(r, MAC_PCS_XXV_GTY_LOOP_1_GT_LOOP);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_1);
+		rf->mp_reg_gty_ctl_rx = r;
+		rf->mp_fld_gty_ctl_rx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_POLARITY);
+		rf->mp_fld_gty_ctl_rx_lpm_en = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_LPM_EN);
+		rf->mp_fld_gty_ctl_rx_equa_rst = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_1_EQUA_RST);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_1);
+		rf->mp_fld_gty_ctl_tx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_1_POLARITY);
+		rf->mp_fld_gty_ctl_tx_inhibit = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_1_INHIBIT);
+
+		if (!mac_8x10G) {
+			r = get_register(module, MAC_PCS_XXV_LINK_SPEED_1);
+			rf->mp_reg_link_speed = get_register(module, MAC_PCS_XXV_LINK_SPEED_1);
+
+			rf->mp_fld_link_speed_10g = get_field(r, MAC_PCS_XXV_LINK_SPEED_1_SPEED);
+
+			if (!rf->mp_fld_link_speed_10g) {
+				rf->mp_fld_link_speed_10g =
+					get_field(r, MAC_PCS_XXV_LINK_SPEED_1_10G);
+			}
+
+			rf->mp_fld_link_speed_toggle =
+				get_field(r, MAC_PCS_XXV_LINK_SPEED_1_TOGGLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_1);
+			rf->mp_reg_rs_fec_conf = r;
+			rf->mp_fld_rs_fec_conf_rs_fec_enable =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CONF_1_RS_FEC_ENABLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_1);
+			rf->mp_reg_rs_fec_ccw = r;
+			rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_1_RS_FEC_CCW_CNT);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_1);
+			rf->mp_reg_rs_fec_ucw = r;
+			rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_1_RS_FEC_UCW_CNT);
+		}
+	}
+
+	if (n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+
+		r = get_register(module, MAC_PCS_XXV_GTY_LOOP_2);
+		rf->mp_reg_gty_loop = r;
+		rf->mp_fld_gty_loop_gt_loop = get_field(r, MAC_PCS_XXV_GTY_LOOP_2_GT_LOOP);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_2);
+		rf->mp_reg_gty_ctl_rx = r;
+		rf->mp_fld_gty_ctl_rx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_POLARITY);
+		rf->mp_fld_gty_ctl_rx_lpm_en = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_LPM_EN);
+		rf->mp_fld_gty_ctl_rx_equa_rst = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_2_EQUA_RST);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_2);
+		rf->mp_fld_gty_ctl_tx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_2_POLARITY);
+		rf->mp_fld_gty_ctl_tx_inhibit = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_2_INHIBIT);
+
+		if (!mac_8x10G) {
+			r = get_register(module, MAC_PCS_XXV_LINK_SPEED_2);
+			rf->mp_reg_link_speed = get_register(module, MAC_PCS_XXV_LINK_SPEED_2);
+
+			rf->mp_fld_link_speed_10g = get_field(r, MAC_PCS_XXV_LINK_SPEED_2_SPEED);
+
+			if (!rf->mp_fld_link_speed_10g) {
+				rf->mp_fld_link_speed_10g =
+					get_field(r, MAC_PCS_XXV_LINK_SPEED_2_10G);
+			}
+
+			rf->mp_fld_link_speed_toggle =
+				get_field(r, MAC_PCS_XXV_LINK_SPEED_2_TOGGLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_2);
+			rf->mp_reg_rs_fec_conf = r;
+			rf->mp_fld_rs_fec_conf_rs_fec_enable =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CONF_2_RS_FEC_ENABLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_2);
+			rf->mp_reg_rs_fec_ccw = r;
+			rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_2_RS_FEC_CCW_CNT);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_2);
+			rf->mp_reg_rs_fec_ucw = r;
+			rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_2_RS_FEC_UCW_CNT);
+		}
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+
+		r = get_register(module, MAC_PCS_XXV_GTY_LOOP_3);
+		rf->mp_reg_gty_loop = r;
+		rf->mp_fld_gty_loop_gt_loop = get_field(r, MAC_PCS_XXV_GTY_LOOP_3_GT_LOOP);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_RX_3);
+		rf->mp_reg_gty_ctl_rx = r;
+		rf->mp_fld_gty_ctl_rx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_POLARITY);
+		rf->mp_fld_gty_ctl_rx_lpm_en = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_LPM_EN);
+		rf->mp_fld_gty_ctl_rx_equa_rst = get_field(r, MAC_PCS_XXV_GTY_CTL_RX_3_EQUA_RST);
+
+		r = get_register(module, MAC_PCS_XXV_GTY_CTL_TX_3);
+		rf->mp_fld_gty_ctl_tx_polarity = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_3_POLARITY);
+		rf->mp_fld_gty_ctl_tx_inhibit = get_field(r, MAC_PCS_XXV_GTY_CTL_TX_3_INHIBIT);
+
+		if (!mac_8x10G) {
+			r = get_register(module, MAC_PCS_XXV_LINK_SPEED_3);
+			rf->mp_reg_link_speed = get_register(module, MAC_PCS_XXV_LINK_SPEED_3);
+
+			rf->mp_fld_link_speed_10g = get_field(r, MAC_PCS_XXV_LINK_SPEED_3_SPEED);
+
+			if (!rf->mp_fld_link_speed_10g) {
+				rf->mp_fld_link_speed_10g =
+					get_field(r, MAC_PCS_XXV_LINK_SPEED_3_10G);
+			}
+
+			rf->mp_fld_link_speed_toggle =
+				get_field(r, MAC_PCS_XXV_LINK_SPEED_3_TOGGLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CONF_3);
+			rf->mp_reg_rs_fec_conf = r;
+			rf->mp_fld_rs_fec_conf_rs_fec_enable =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CONF_3_RS_FEC_ENABLE);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_CCW_CNT_3);
+			rf->mp_reg_rs_fec_ccw = r;
+			rf->mp_field_reg_rs_fec_ccw_reg_rs_fec_ccw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_CCW_CNT_3_RS_FEC_CCW_CNT);
+
+			r = get_register(module, MAC_PCS_XXV_RS_FEC_UCW_CNT_3);
+			rf->mp_reg_rs_fec_ucw = r;
+			rf->mp_field_reg_rs_fec_ucw_reg_rs_fec_ucw_cnt =
+				get_field(r, MAC_PCS_XXV_RS_FEC_UCW_CNT_3_RS_FEC_UCW_CNT);
+		}
+	}
+
+	/*
+	 * Registers MAC_PCS_XXV_DEBOUNCE_CTRL_0 -- MAC_PCS_XXV_DEBOUNCE_CTRL_3
+	 * and       MAC_PCS_XXV_TIMESTAMP_COMP_0 -- MAC_PCS_XXV_TIMESTAMP_COMP_3
+	 * and       MAC_PCS_XXV_GTY_PRE_CURSOR_0 -- MAC_PCS_XXV_GTY_PRE_CURSOR_3
+	 * and       MAC_PCS_XXV_GTY_DIFF_CTL_0 -- MAC_PCS_XXV_GTY_DIFF_CTL_0
+	 * and       MAC_PCS_XXV_GTY_POST_CURSOR_0 -- MAC_PCS_XXV_GTY_POST_CURSOR_3
+	 */
+	if (n_channels <= 4) {
+		/* Initialize regs/fields for sub-module/channel 0 */
+		rf = &p->regs[0];
+
+		r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_0);
+
+		rf->mp_reg_debounce_ctrl = r;
+		rf->mp_field_debounce_ctrl_nt_port_ctrl =
+			get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_0_NT_PORT_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_0);
+		rf->mp_reg_timestamp_comp = r;
+		rf->mp_field_timestamp_comp_rx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_0_RX_DLY);
+		rf->mp_field_timestamp_comp_tx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_0_TX_DLY);
+
+		/* GTY_PRE_CURSOR */
+		r = get_register(p->mp_mod_mac_pcs_xxv, MAC_PCS_XXV_GTY_PRE_CURSOR_0);
+		rf->mp_reg_gty_pre_cursor = r;
+		rf->mp_field_gty_pre_cursor_tx_pre_csr =
+			get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_0_TX_PRE_CSR);
+
+		/* GTY_DIFF_CTL */
+		r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_0);
+		rf->mp_reg_gty_diff_ctl = r;
+		rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl =
+			get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_0_TX_DIFF_CTL);
+
+		/* GTY_POST_CURSOR */
+		r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_0);
+		rf->mp_reg_gty_post_cursor = r;
+		rf->mp_field_gty_post_cursor_tx_post_csr =
+			get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_0_TX_POST_CSR);
+	}
+
+	if (n_channels >= 2) {
+		/* Initialize regs/fields for sub-module/channel 1 */
+		rf = &p->regs[1];
+
+		r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_1);
+
+		rf->mp_reg_debounce_ctrl = r;
+		rf->mp_field_debounce_ctrl_nt_port_ctrl =
+			get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_1_NT_PORT_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_1);
+		rf->mp_reg_timestamp_comp = r;
+		rf->mp_field_timestamp_comp_rx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_1_RX_DLY);
+		rf->mp_field_timestamp_comp_tx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_1_TX_DLY);
+
+		/* GTY_PRE_CURSOR */
+		r = get_register(p->mp_mod_mac_pcs_xxv, MAC_PCS_XXV_GTY_PRE_CURSOR_1);
+		rf->mp_reg_gty_pre_cursor = r;
+		rf->mp_field_gty_pre_cursor_tx_pre_csr =
+			get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_1_TX_PRE_CSR);
+
+		/* GTY_DIFF_CTL */
+		r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_1);
+		rf->mp_reg_gty_diff_ctl = r;
+		rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl =
+			get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_1_TX_DIFF_CTL);
+
+		/* GTY_POST_CURSOR */
+		r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_1);
+		rf->mp_reg_gty_post_cursor = r;
+		rf->mp_field_gty_post_cursor_tx_post_csr =
+			get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_1_TX_POST_CSR);
+	}
+
+	if (n_channels == 4) {
+		/* Initialize regs/fields for sub-module/channel 2 */
+		rf = &p->regs[2];
+
+		r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_2);
+
+		rf->mp_reg_debounce_ctrl = r;
+		rf->mp_field_debounce_ctrl_nt_port_ctrl =
+			get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_2_NT_PORT_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_2);
+		rf->mp_reg_timestamp_comp = r;
+		rf->mp_field_timestamp_comp_rx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_2_RX_DLY);
+		rf->mp_field_timestamp_comp_tx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_2_TX_DLY);
+
+		/* GTY_PRE_CURSOR */
+		r = get_register(p->mp_mod_mac_pcs_xxv, MAC_PCS_XXV_GTY_PRE_CURSOR_2);
+		rf->mp_reg_gty_pre_cursor = r;
+		rf->mp_field_gty_pre_cursor_tx_pre_csr =
+			get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_2_TX_PRE_CSR);
+
+		/* GTY_DIFF_CTL */
+		r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_2);
+		rf->mp_reg_gty_diff_ctl = r;
+		rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl =
+			get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_2_TX_DIFF_CTL);
+
+		/* GTY_POST_CURSOR */
+		r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_2);
+		rf->mp_reg_gty_post_cursor = r;
+		rf->mp_field_gty_post_cursor_tx_post_csr =
+			get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_2_TX_POST_CSR);
+
+		/* Initialize regs/fields for sub-module/channel 3 */
+		rf = &p->regs[3];
+
+		r = get_register(module, MAC_PCS_XXV_DEBOUNCE_CTRL_3);
+
+		rf->mp_reg_debounce_ctrl = r;
+		rf->mp_field_debounce_ctrl_nt_port_ctrl =
+			get_field(r, MAC_PCS_XXV_DEBOUNCE_CTRL_3_NT_PORT_CTRL);
+
+		r = get_register(module, MAC_PCS_XXV_TIMESTAMP_COMP_3);
+		rf->mp_reg_timestamp_comp = r;
+		rf->mp_field_timestamp_comp_rx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_3_RX_DLY);
+		rf->mp_field_timestamp_comp_tx_dly =
+			get_field(r, MAC_PCS_XXV_TIMESTAMP_COMP_3_TX_DLY);
+
+		/* GTY_PRE_CURSOR */
+		r = get_register(p->mp_mod_mac_pcs_xxv, MAC_PCS_XXV_GTY_PRE_CURSOR_3);
+		rf->mp_reg_gty_pre_cursor = r;
+		rf->mp_field_gty_pre_cursor_tx_pre_csr =
+			get_field(r, MAC_PCS_XXV_GTY_PRE_CURSOR_3_TX_PRE_CSR);
+
+		/* GTY_DIFF_CTL */
+		r = get_register(module, MAC_PCS_XXV_GTY_DIFF_CTL_3);
+		rf->mp_reg_gty_diff_ctl = r;
+		rf->mp_field_gty_gty_diff_ctl_tx_diff_ctl =
+			get_field(r, MAC_PCS_XXV_GTY_DIFF_CTL_3_TX_DIFF_CTL);
+
+		/* GTY_POST_CURSOR */
+		r = get_register(module, MAC_PCS_XXV_GTY_POST_CURSOR_3);
+		rf->mp_reg_gty_post_cursor = r;
+		rf->mp_field_gty_post_cursor_tx_post_csr =
+			get_field(r, MAC_PCS_XXV_GTY_POST_CURSOR_3_TX_POST_CSR);
+	}
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_pcie3.c b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
new file mode 100644
index 0000000000..533d3046de
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_pcie3.c
@@ -0,0 +1,270 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_pcie3.h"
+
+#define NTHW_TG_REF_FREQ (250000000ULL)
+
+nthw_pcie3_t *nthw_pcie3_new(void)
+{
+	nthw_pcie3_t *p = malloc(sizeof(nthw_pcie3_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_pcie3_t));
+
+	return p;
+}
+
+void nthw_pcie3_delete(nthw_pcie3_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_pcie3_t));
+		free(p);
+	}
+}
+
+int nthw_pcie3_init(nthw_pcie3_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_PCIE3, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: PCIE3 %d: no such instance\n",
+			p_fpga->p_fpga_info->mp_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_pcie3 = mod;
+
+	/* PCIe3 */
+	p->mp_reg_stat_ctrl = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_CTRL);
+	p->mp_fld_stat_ctrl_ena =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_ENA);
+	p->mp_fld_stat_ctrl_req =
+		nthw_register_get_field(p->mp_reg_stat_ctrl, PCIE3_STAT_CTRL_STAT_REQ);
+
+	p->mp_reg_stat_rx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RX);
+	p->mp_fld_stat_rx_counter =
+		nthw_register_get_field(p->mp_reg_stat_rx, PCIE3_STAT_RX_COUNTER);
+
+	p->mp_reg_stat_tx = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_TX);
+	p->mp_fld_stat_tx_counter =
+		nthw_register_get_field(p->mp_reg_stat_tx, PCIE3_STAT_TX_COUNTER);
+
+	p->mp_reg_stat_ref_clk = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_REFCLK);
+	p->mp_fld_stat_ref_clk_ref_clk =
+		nthw_register_get_field(p->mp_reg_stat_ref_clk, PCIE3_STAT_REFCLK_REFCLK250);
+
+	p->mp_reg_stat_rq_rdy = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_RDY);
+	p->mp_fld_stat_rq_rdy_counter =
+		nthw_register_get_field(p->mp_reg_stat_rq_rdy, PCIE3_STAT_RQ_RDY_COUNTER);
+
+	p->mp_reg_stat_rq_vld = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STAT_RQ_VLD);
+	p->mp_fld_stat_rq_vld_counter =
+		nthw_register_get_field(p->mp_reg_stat_rq_vld, PCIE3_STAT_RQ_VLD_COUNTER);
+
+	p->mp_reg_status0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_STATUS0);
+	p->mp_fld_status0_tags_in_use =
+		nthw_register_get_field(p->mp_reg_status0, PCIE3_STATUS0_TAGS_IN_USE);
+
+	p->mp_reg_rp_to_ep_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_RP_TO_EP_ERR);
+	p->mp_fld_rp_to_ep_err_cor =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_COR);
+	p->mp_fld_rp_to_ep_err_non_fatal =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_NONFATAL);
+	p->mp_fld_rp_to_ep_err_fatal =
+		nthw_register_get_field(p->mp_reg_rp_to_ep_err, PCIE3_RP_TO_EP_ERR_ERR_FATAL);
+
+	p->mp_reg_ep_to_rp_err = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_EP_TO_RP_ERR);
+	p->mp_fld_ep_to_rp_err_cor =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_COR);
+	p->mp_fld_ep_to_rp_err_non_fatal =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_NONFATAL);
+	p->mp_fld_ep_to_rp_err_fatal =
+		nthw_register_get_field(p->mp_reg_ep_to_rp_err, PCIE3_EP_TO_RP_ERR_ERR_FATAL);
+
+	p->mp_reg_sample_time = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_SAMPLE_TIME);
+	p->mp_fld_sample_time =
+		nthw_register_get_field(p->mp_reg_sample_time, PCIE3_SAMPLE_TIME_SAMPLE_TIME);
+
+	p->mp_reg_pci_end_point = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_ENDPOINT);
+	p->mp_fld_pci_end_point_if_id =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_IF_ID);
+	p->mp_fld_pci_end_point_send_msg =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_SEND_MSG);
+	p->mp_fld_pci_end_point_get_msg =
+		nthw_register_get_field(p->mp_reg_pci_end_point, PCIE3_PCI_ENDPOINT_GET_MSG);
+	p->mp_fld_pci_end_point_dmaep0_allow_mask =
+		nthw_register_get_field(p->mp_reg_pci_end_point,
+			PCIE3_PCI_ENDPOINT_DMA_EP0_ALLOW_MASK);
+	p->mp_fld_pci_end_point_dmaep1_allow_mask =
+		nthw_register_get_field(p->mp_reg_pci_end_point,
+			PCIE3_PCI_ENDPOINT_DMA_EP1_ALLOW_MASK);
+
+	if (p->mp_reg_pci_end_point)
+		nthw_register_update(p->mp_reg_pci_end_point);
+
+	p->mp_reg_pci_test0 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST0);
+	p->mp_fld_pci_test0 = nthw_register_get_field(p->mp_reg_pci_test0, PCIE3_PCI_TEST0_DATA);
+
+	if (p->mp_reg_pci_test0)
+		nthw_register_update(p->mp_reg_pci_test0);
+
+	p->mp_reg_pci_test1 = nthw_module_get_register(p->mp_mod_pcie3, PCIE3_PCI_TEST1);
+	p->mp_fld_pci_test1 = nthw_register_get_field(p->mp_reg_pci_test1, PCIE3_PCI_TEST1_DATA);
+
+	if (p->mp_reg_pci_test1)
+		nthw_register_update(p->mp_reg_pci_test1);
+
+	p->mp_reg_pci_e3_mark_adr_lsb =
+		nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_LSB);
+	p->mp_fld_pci_e3_mark_adr_lsb_adr =
+		nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_lsb, PCIE3_MARKADR_LSB_ADR);
+
+	if (p->mp_reg_pci_e3_mark_adr_lsb)
+		nthw_register_update(p->mp_reg_pci_e3_mark_adr_lsb);
+
+	p->mp_reg_pci_e3_mark_adr_msb =
+		nthw_module_get_register(p->mp_mod_pcie3, PCIE3_MARKADR_MSB);
+	p->mp_fld_pci_e3_mark_adr_msb_adr =
+		nthw_register_get_field(p->mp_reg_pci_e3_mark_adr_msb, PCIE3_MARKADR_MSB_ADR);
+
+	if (p->mp_reg_pci_e3_mark_adr_msb)
+		nthw_register_update(p->mp_reg_pci_e3_mark_adr_msb);
+
+	/* Initial setup - disable markerscheme and bifurcation */
+	if (p->mp_fld_pci_end_point_dmaep0_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask);
+
+	if (p->mp_fld_pci_end_point_dmaep1_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask);
+
+	if (p->mp_fld_pci_e3_mark_adr_lsb_adr)
+		nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_lsb_adr, 0UL);
+
+	if (p->mp_fld_pci_e3_mark_adr_msb_adr)
+		nthw_field_set_val_flush32(p->mp_fld_pci_e3_mark_adr_msb_adr, 0UL);
+
+	if (p->mp_fld_pci_end_point_dmaep0_allow_mask)
+		nthw_field_set_flush(p->mp_fld_pci_end_point_dmaep0_allow_mask);
+
+	if (p->mp_fld_pci_end_point_dmaep1_allow_mask)
+		nthw_field_clr_flush(p->mp_fld_pci_end_point_dmaep1_allow_mask);
+
+	return 0;
+};
+
+int nthw_pcie3_trigger_sample_time(nthw_pcie3_t *p)
+{
+	nthw_field_set_val_flush32(p->mp_fld_sample_time, 0xfee1dead);
+
+	return 0;
+}
+
+int nthw_pcie3_stat_req_enable(nthw_pcie3_t *p)
+{
+	nthw_field_set_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_pcie3_stat_req_disable(nthw_pcie3_t *p)
+{
+	nthw_field_clr_all(p->mp_fld_stat_ctrl_ena);
+	nthw_field_set_all(p->mp_fld_stat_ctrl_req);
+	nthw_field_flush_register(p->mp_fld_stat_ctrl_req);
+	return 0;
+}
+
+int nthw_pcie3_get_stat(nthw_pcie3_t *p, uint32_t *p_rx_cnt, uint32_t *p_tx_cnt,
+	uint32_t *p_ref_clk_cnt, uint32_t *p_tg_unit_size, uint32_t *p_tg_ref_freq,
+	uint32_t *p_tag_use_cnt, uint32_t *p_rq_rdy_cnt, uint32_t *p_rq_vld_cnt)
+{
+	*p_rx_cnt = nthw_field_get_updated(p->mp_fld_stat_rx_counter);
+	*p_tx_cnt = nthw_field_get_updated(p->mp_fld_stat_tx_counter);
+
+	*p_ref_clk_cnt = nthw_field_get_updated(p->mp_fld_stat_ref_clk_ref_clk);
+
+	*p_tg_unit_size = NTHW_TG_CNT_SIZE;
+	*p_tg_ref_freq = NTHW_TG_REF_FREQ;
+
+	*p_tag_use_cnt = nthw_field_get_updated(p->mp_fld_status0_tags_in_use);
+
+	*p_rq_rdy_cnt = nthw_field_get_updated(p->mp_fld_stat_rq_rdy_counter);
+	*p_rq_vld_cnt = nthw_field_get_updated(p->mp_fld_stat_rq_vld_counter);
+
+	return 0;
+}
+
+int nthw_pcie3_get_stat_rate(nthw_pcie3_t *p, uint64_t *p_pci_rx_rate, uint64_t *p_pci_tx_rate,
+	uint64_t *p_ref_clk_cnt, uint64_t *p_tag_use_cnt,
+	uint64_t *p_pci_nt_bus_util, uint64_t *p_pci_xil_bus_util)
+{
+	uint32_t rx_cnt, tx_cnt, ref_clk_cnt;
+	uint32_t tg_unit_size, tg_ref_freq;
+	uint32_t tag_use_cnt, rq_rdy_cnt, rq_vld_cnt;
+
+	nthw_pcie3_get_stat(p, &rx_cnt, &tx_cnt, &ref_clk_cnt, &tg_unit_size, &tg_ref_freq,
+		&tag_use_cnt, &rq_rdy_cnt, &rq_vld_cnt);
+
+	if (ref_clk_cnt) {
+		uint64_t nt_bus_util, xil_bus_util;
+		uint64_t rx_rate, tx_rate;
+
+		rx_rate = ((uint64_t)rx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_rx_rate = rx_rate;
+
+		tx_rate = ((uint64_t)tx_cnt * tg_unit_size * tg_ref_freq) / (uint64_t)ref_clk_cnt;
+		*p_pci_tx_rate = tx_rate;
+
+		*p_ref_clk_cnt = ref_clk_cnt;
+
+		*p_tag_use_cnt = tag_use_cnt;
+
+		nt_bus_util = ((uint64_t)rq_vld_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt;
+		*p_pci_nt_bus_util = nt_bus_util;
+		xil_bus_util = ((uint64_t)rq_rdy_cnt * 1000000ULL) / (uint64_t)ref_clk_cnt;
+		*p_pci_xil_bus_util = xil_bus_util;
+
+	} else {
+		*p_ref_clk_cnt = 0;
+		*p_pci_nt_bus_util = 0;
+		*p_pci_xil_bus_util = 0;
+	}
+
+	return 0;
+}
+
+int nthw_pcie3_end_point_counters_sample_pre(nthw_pcie3_t *p,
+	struct nthw_hif_end_point_counters *epc)
+{
+	NT_LOG(DBG, NTHW, "%s:%u: empty function\n", __func__, __LINE__);
+
+	(void)p;
+	(void)epc;
+
+	return 0;
+}
+
+int nthw_pcie3_end_point_counters_sample_post(nthw_pcie3_t *p,
+	struct nthw_hif_end_point_counters *epc)
+{
+	NT_LOG(DBG, NTHW, "%s:%u:\n", __func__, __LINE__);
+	assert(epc);
+	nthw_pcie3_get_stat_rate(p, &epc->cur_tx, &epc->cur_rx, &epc->n_ref_clk_cnt,
+		&epc->n_tags_in_use, &epc->cur_pci_nt_util,
+		&epc->cur_pci_xil_util);
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_sdc.c b/drivers/net/ntnic/nthw/core/nthw_sdc.c
new file mode 100644
index 0000000000..7666af7e5a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_sdc.c
@@ -0,0 +1,176 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_sdc.h"
+
+nthw_sdc_t *nthw_sdc_new(void)
+{
+	nthw_sdc_t *p = malloc(sizeof(nthw_sdc_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_sdc_t));
+
+	return p;
+}
+
+void nthw_sdc_delete(nthw_sdc_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_sdc_t));
+		free(p);
+	}
+}
+
+int nthw_sdc_init(nthw_sdc_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_SDC, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: SDC %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_sdc = mod;
+
+	{
+		nthw_register_t *p_reg;
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_CTRL);
+		p->mp_fld_ctrl_init = nthw_register_get_field(p_reg, SDC_CTRL_INIT);
+		p->mp_fld_ctrl_run_test = nthw_register_get_field(p_reg, SDC_CTRL_RUN_TEST);
+		p->mp_fld_ctrl_stop_client = nthw_register_get_field(p_reg, SDC_CTRL_STOP_CLIENT);
+		p->mp_fld_ctrl_test_enable = nthw_register_get_field(p_reg, SDC_CTRL_TEST_EN);
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_STAT);
+		p->mp_fld_stat_calib = nthw_register_get_field(p_reg, SDC_STAT_CALIB);
+		p->mp_fld_stat_cell_cnt_stopped =
+			nthw_register_get_field(p_reg, SDC_STAT_CELL_CNT_STOPPED);
+		p->mp_fld_stat_err_found = nthw_register_get_field(p_reg, SDC_STAT_ERR_FOUND);
+		p->mp_fld_stat_init_done = nthw_register_get_field(p_reg, SDC_STAT_INIT_DONE);
+		p->mp_fld_stat_mmcm_lock = nthw_register_get_field(p_reg, SDC_STAT_MMCM_LOCK);
+		p->mp_fld_stat_pll_lock = nthw_register_get_field(p_reg, SDC_STAT_PLL_LOCK);
+		p->mp_fld_stat_resetting = nthw_register_get_field(p_reg, SDC_STAT_RESETTING);
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_CELL_CNT);
+		p->mp_fld_cell_cnt = nthw_register_get_field(p_reg, SDC_CELL_CNT_CELL_CNT);
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_CELL_CNT_PERIOD);
+		p->mp_fld_cell_cnt_period =
+			nthw_register_get_field(p_reg, SDC_CELL_CNT_PERIOD_CELL_CNT_PERIOD);
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_FILL_LVL);
+		p->mp_fld_fill_level = nthw_register_get_field(p_reg, SDC_FILL_LVL_FILL_LVL);
+
+		p_reg = nthw_module_get_register(p->mp_mod_sdc, SDC_MAX_FILL_LVL);
+		p->mp_fld_max_fill_level =
+			nthw_register_get_field(p_reg, SDC_MAX_FILL_LVL_MAX_FILL_LVL);
+	}
+	return 0;
+}
+
+int nthw_sdc_get_states(nthw_sdc_t *p, uint64_t *pn_result_mask)
+{
+	int n_err_cnt = 0;
+	uint64_t n_mask = 0;
+	uint32_t val;
+	uint32_t val_mask;
+	int n_val_width;
+
+	if (!p || !pn_result_mask)
+		return -1;
+
+	val = nthw_field_get_updated(p->mp_fld_stat_calib);
+	n_val_width = nthw_field_get_bit_width(p->mp_fld_stat_calib);
+	val_mask = ((1 << n_val_width) - 1);
+	n_mask = (n_mask << n_val_width) | (val & val_mask);
+
+	if (val != val_mask)
+		n_err_cnt++;
+
+	val = nthw_field_get_updated(p->mp_fld_stat_init_done);
+	n_val_width = nthw_field_get_bit_width(p->mp_fld_stat_init_done);
+	val_mask = ((1 << n_val_width) - 1);
+	n_mask = (n_mask << n_val_width) | (val & val_mask);
+
+	if (val != val_mask)
+		n_err_cnt++;
+
+	val = nthw_field_get_updated(p->mp_fld_stat_mmcm_lock);
+	n_val_width = nthw_field_get_bit_width(p->mp_fld_stat_mmcm_lock);
+	val_mask = ((1 << n_val_width) - 1);
+	n_mask = (n_mask << n_val_width) | (val & val_mask);
+
+	if (val != val_mask)
+		n_err_cnt++;
+
+	val = nthw_field_get_updated(p->mp_fld_stat_pll_lock);
+	n_val_width = nthw_field_get_bit_width(p->mp_fld_stat_pll_lock);
+	val_mask = ((1 << n_val_width) - 1);
+	n_mask = (n_mask << n_val_width) | (val & val_mask);
+
+	if (val != val_mask)
+		n_err_cnt++;
+
+	val = nthw_field_get_updated(p->mp_fld_stat_resetting);
+	n_val_width = nthw_field_get_bit_width(p->mp_fld_stat_resetting);
+	val_mask = ((1 << n_val_width) - 1);
+	n_mask = (n_mask << n_val_width) | (val & val_mask);
+
+	if (val != 0)
+		n_err_cnt++;
+
+	if (pn_result_mask)
+		*pn_result_mask = n_mask;
+
+	return n_err_cnt;	/* 0 = all ok */
+}
+
+int nthw_sdc_wait_states(nthw_sdc_t *p, const int n_poll_iterations, const int n_poll_interval)
+{
+	int res;
+	int n_err_cnt = 0;
+
+	res = nthw_field_wait_set_all32(p->mp_fld_stat_calib, n_poll_iterations, n_poll_interval);
+
+	if (res)
+		n_err_cnt++;
+
+	res = nthw_field_wait_set_all32(p->mp_fld_stat_init_done, n_poll_iterations,
+			n_poll_interval);
+
+	if (res)
+		n_err_cnt++;
+
+	res = nthw_field_wait_set_all32(p->mp_fld_stat_mmcm_lock, n_poll_iterations,
+			n_poll_interval);
+
+	if (res)
+		n_err_cnt++;
+
+	res = nthw_field_wait_set_all32(p->mp_fld_stat_pll_lock, n_poll_iterations,
+			n_poll_interval);
+
+	if (res)
+		n_err_cnt++;
+
+	res = nthw_field_wait_clr_all32(p->mp_fld_stat_resetting, n_poll_iterations,
+			n_poll_interval);
+
+	if (res)
+		n_err_cnt++;
+
+	return n_err_cnt;	/* 0 = all ok */
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_si5340.c b/drivers/net/ntnic/nthw/core/nthw_si5340.c
new file mode 100644
index 0000000000..9f5a801ddf
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_si5340.c
@@ -0,0 +1,205 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ *
+ * This file implements Si5340 clock synthesizer support.
+ * The implementation is generic and must be tailored to a specific use by the
+ * correct initialization data.
+ */
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_si5340.h"
+
+#define SI5340_WAIT_US(x) nt_os_wait_usec(x)
+
+#define SI5340_LOG_DEBUG(...) NT_LOG(DBG, NTHW, __VA_ARGS__)
+#define SI5340_LOG_INFO(...) NT_LOG(INF, NTHW, __VA_ARGS__)
+#define SI5340_LOG_WARN(...) NT_LOG(WRN, NTHW, __VA_ARGS__)
+#define SI5340_LOG_ERROR(...) NT_LOG(ERR, NTHW, __VA_ARGS__)
+
+#define SI5340_PAGE_REG_ADDR (0x01)
+
+nthw_si5340_t *nthw_si5340_new(void)
+{
+	nthw_si5340_t *p = malloc(sizeof(nthw_si5340_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_si5340_t));
+
+	return p;
+}
+
+int nthw_si5340_init(nthw_si5340_t *p, nthw_iic_t *p_nthw_iic, uint8_t n_iic_addr)
+{
+	uint8_t data;
+
+	p->mp_nthw_iic = p_nthw_iic;
+	p->mn_iic_addr = n_iic_addr;
+	p->mn_clk_cfg = -1;
+
+	p->m_si5340_page = 0;
+	data = p->m_si5340_page;
+	nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, SI5340_PAGE_REG_ADDR, 1, &data);
+
+	return 0;
+}
+
+void nthw_si5340_delete(nthw_si5340_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_si5340_t));
+		free(p);
+	}
+}
+
+/*
+ * Read access (via I2C) to the clock synthesizer IC. The IC is located at I2C
+ * 7bit address 0x74
+ */
+static uint8_t nthw_si5340_read(nthw_si5340_t *p, uint16_t reg_addr)
+{
+	const uint8_t offset_adr = (uint8_t)(reg_addr & 0xff);
+	uint8_t page = (uint8_t)((reg_addr >> 8) & 0xff);
+	uint8_t data;
+
+	/* check if we are on the right page */
+	if (page != p->m_si5340_page) {
+		nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, SI5340_PAGE_REG_ADDR, 1,
+			&page);
+		p->m_si5340_page = page;
+	}
+
+	nthw_iic_read_data(p->mp_nthw_iic, p->mn_iic_addr, offset_adr, 1, &data);
+	return data;
+}
+
+/*
+ * Write access (via I2C) to the clock synthesizer IC. The IC is located at I2C
+ * 7 bit address 0x74
+ */
+static int nthw_si5340_write(nthw_si5340_t *p, uint16_t reg_addr, uint8_t data)
+{
+	const uint8_t offset_adr = (uint8_t)(reg_addr & 0xff);
+	uint8_t page = (uint8_t)((reg_addr >> 8) & 0xff);
+
+	/* check if we are on the right page */
+	if (page != p->m_si5340_page) {
+		nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, SI5340_PAGE_REG_ADDR, 1,
+			&page);
+		p->m_si5340_page = page;
+	}
+
+	nthw_iic_write_data(p->mp_nthw_iic, p->mn_iic_addr, offset_adr, 1, &data);
+
+	return 0;
+}
+
+static int nthw_si5340_cfg(nthw_si5340_t *p, const void *p_data, int data_cnt,
+	clk_profile_data_fmt_t data_format)
+{
+	const char *const p_adapter_id_str =
+		p->mp_nthw_iic->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	int i;
+	uint16_t addr;
+	uint8_t value;
+	uint8_t ctrl_value;
+
+	NT_LOG(DBG, NTHW, "%s: %s: data_cnt = %d, data_format = %d\n", p_adapter_id_str, __func__,
+		data_cnt, data_format);
+
+	for (i = 0; i < data_cnt; i++) {
+		if (data_format == clk_profile_data_fmt_1) {
+			addr = ((const clk_profile_data_fmt1_t *)p_data)->reg_addr;
+			value = ((const clk_profile_data_fmt1_t *)p_data)->reg_val;
+			p_data = ((const clk_profile_data_fmt1_t *)p_data) + 1;
+
+		} else if (data_format == clk_profile_data_fmt_2) {
+			addr = (uint16_t)(((const clk_profile_data_fmt2_t *)p_data)->reg_addr);
+			value = ((const clk_profile_data_fmt2_t *)p_data)->reg_val;
+			p_data = ((const clk_profile_data_fmt2_t *)p_data) + 1;
+
+		} else {
+			NT_LOG(ERR, NTHW, "%s: Unhandled Si5340 data format (%d)\n",
+				p_adapter_id_str, data_format);
+			return -1;
+		}
+
+		if (addr == 0x0006) {
+			/* Wait 300ms before continuing. See NT200E3-2-PTP_U23_Si5340_adr0_v2.h */
+			nt_os_wait_usec(300000);
+		}
+
+		nthw_si5340_write(p, addr, value);
+
+		if (addr == 0x001C) {
+			/* skip readback for "soft reset" register */
+			continue;
+		}
+
+		ctrl_value = nthw_si5340_read(p, addr);
+
+		if (ctrl_value != value) {
+			NT_LOG(ERR, NTHW,
+				"%s: Si5340 configuration readback check failed. (Addr = 0x%04X, Write = 0x%02X, Read = 0x%02X)\n",
+				p_adapter_id_str, addr, value, ctrl_value);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int nthw_si5340_config(nthw_si5340_t *p, const void *p_data, int data_cnt,
+	clk_profile_data_fmt_t data_format)
+{
+	const char *const p_adapter_id_str =
+		p->mp_nthw_iic->mp_fpga->p_fpga_info->mp_adapter_id_str;
+	int i;
+	bool success = false;
+	uint8_t status, sticky;
+	uint8_t design_id[9];
+
+	(void)nthw_si5340_cfg(p, p_data, data_cnt, data_format);
+
+	/* Check if DPLL is locked and SYS is calibrated */
+	for (i = 0; i < 5; i++) {
+		status = nthw_si5340_read(p, 0x0c);
+		sticky = nthw_si5340_read(p, 0x11);
+		nthw_si5340_write(p, 0x11, 0x00);
+
+		if (((status & 0x09) == 0x00) && ((sticky & 0x09) == 0x00)) {
+			success = true;
+			break;
+		}
+
+		nt_os_wait_usec(1000000);	/* 1 sec */
+	}
+
+	if (!success) {
+		NT_LOG(ERR, NTHW,
+			"%s: Si5340 configuration failed. (Status = 0x%02X, Sticky = 0x%02X)\n",
+			p_adapter_id_str, status, sticky);
+		return -1;
+	}
+
+	for (i = 0; i < (int)sizeof(design_id) - 1; i++)
+		design_id[i] = nthw_si5340_read(p, (uint16_t)(0x26B + i));
+
+	design_id[sizeof(design_id) - 1] = 0;
+
+	(void)design_id;/* Only used in debug mode */
+	NT_LOG(DBG, NTHW, "%s: Si5340.Design_id = %s\n", p_adapter_id_str, design_id);
+
+	return 0;
+}
+
+int nthw_si5340_config_fmt2(nthw_si5340_t *p, const clk_profile_data_fmt2_t *p_data,
+	const int data_cnt)
+{
+	return nthw_si5340_config(p, p_data, data_cnt, clk_profile_data_fmt_2);
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_spi_v3.c b/drivers/net/ntnic/nthw/core/nthw_spi_v3.c
new file mode 100644
index 0000000000..1d49eea36b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spi_v3.c
@@ -0,0 +1,356 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_fpga.h"
+
+#include "nthw_spi_v3.h"
+
+#include <arpa/inet.h>
+
+#undef SPI_V3_DEBUG_PRINT
+
+nthw_spi_v3_t *nthw_spi_v3_new(void)
+{
+	nthw_spi_v3_t *p = malloc(sizeof(nthw_spi_v3_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_spi_v3_t));
+
+	return p;
+}
+
+int nthw_spi_v3_set_timeout(nthw_spi_v3_t *p, int time_out)
+{
+	p->m_time_out = time_out;
+	return 0;
+}
+
+/*
+ * Wait until Tx data have been sent after they have been placed in the Tx FIFO.
+ */
+static int wait_for_tx_data_sent(nthw_spim_t *p_spim_mod, uint64_t time_out)
+{
+	int result;
+	bool empty;
+	uint64_t start_time;
+	uint64_t cur_time;
+	start_time = nt_os_get_time_monotonic_counter();
+
+	while (true) {
+		nt_os_wait_usec(1000);	/* Every 1ms */
+
+		result = nthw_spim_get_tx_fifo_empty(p_spim_mod, &empty);
+
+		if (result != 0) {
+			NT_LOG(WRN, NTHW, "nthw_spim_get_tx_fifo_empty failed\n");
+			return result;
+		}
+
+		if (empty)
+			break;
+
+		cur_time = nt_os_get_time_monotonic_counter();
+
+		if ((cur_time - start_time) > time_out) {
+			NT_LOG(WRN, NTHW, "%s: Timed out\n", __func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Wait until Rx data have been received.
+ */
+static int wait_for_rx_data_ready(nthw_spis_t *p_spis_mod, uint64_t time_out)
+{
+	int result;
+	bool empty;
+	uint64_t start_time;
+	uint64_t cur_time;
+	start_time = nt_os_get_time_monotonic_counter();
+
+	/* Wait for data to become ready in the Rx FIFO */
+	while (true) {
+		nt_os_wait_usec(10000);	/* Every 10ms */
+
+		result = nthw_spis_get_rx_fifo_empty(p_spis_mod, &empty);
+
+		if (result != 0) {
+			NT_LOG(WRN, NTHW, "nthw_spis_get_rx_empty failed\n");
+			return result;
+		}
+
+		if (!empty)
+			break;
+
+		cur_time = nt_os_get_time_monotonic_counter();
+
+		if ((cur_time - start_time) > time_out) {
+			NT_LOG(WRN, NTHW, "%s: Timed out\n", __func__);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+#ifdef SPI_V3_DEBUG_PRINT
+static void dump_hex(uint8_t *p_data, uint16_t count)
+{
+	int i;
+	int j = 0;
+	char tmp_str[128];
+
+	for (i = 0; i < count; i++) {
+		sprintf(&tmp_str[j * 3], "%02X ", *(p_data++));
+		j++;
+
+		if (j == 16 || i == count - 1) {
+			tmp_str[j * 3 - 1] = '\0';
+			NT_LOG(DBG, NTHW, "    %s\n", tmp_str);
+			j = 0;
+		}
+	}
+}
+#endif
+
+int nthw_spi_v3_init(nthw_spi_v3_t *p, nthw_fpga_t *p_fpga, int n_instance_no)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	uint32_t result;
+
+	p->mn_instance_no = n_instance_no;
+
+	nthw_spi_v3_set_timeout(p, 1);
+
+	/* Initialize SPIM module */
+	p->mp_spim_mod = nthw_spim_new();
+
+	result = nthw_spim_init(p->mp_spim_mod, p_fpga, n_instance_no);
+
+	if (result != 0)
+		NT_LOG(ERR, NTHW, "%s: nthw_spis_init failed: %d\n", p_adapter_id_str, result);
+
+	/* Initialize SPIS module */
+	p->mp_spis_mod = nthw_spis_new();
+
+	result = nthw_spis_init(p->mp_spis_mod, p_fpga, n_instance_no);
+
+	if (result != 0)
+		NT_LOG(ERR, NTHW, "%s: nthw_spim_init failed: %d\n", p_adapter_id_str, result);
+
+	/* Reset SPIM and SPIS modules */
+	result = nthw_spim_reset(p->mp_spim_mod);
+
+	if (result != 0)
+		NT_LOG(ERR, NTHW, "%s: nthw_spim_reset failed: %d\n", p_adapter_id_str, result);
+
+	result = nthw_spis_reset(p->mp_spis_mod);
+
+	if (result != 0)
+		NT_LOG(ERR, NTHW, "%s: nthw_spis_reset failed: %d\n", p_adapter_id_str, result);
+
+	return result;
+}
+
+/*
+ * Send Tx data using the SPIM module and receive any data using the SPIS module.
+ * The data are sent and received being wrapped into a SPI v3 container.
+ */
+int nthw_spi_v3_transfer(nthw_spi_v3_t *p, uint16_t opcode, struct tx_rx_buf *tx_buf,
+	struct tx_rx_buf *rx_buf)
+{
+	const uint16_t max_payload_rx_size = rx_buf->size;
+	int result = 0;
+
+#pragma pack(push, 1)
+	union {
+		uint32_t raw;
+
+		struct {
+			uint16_t opcode;
+			uint16_t size;
+		};
+	} spi_tx_hdr;
+
+	union {
+		uint32_t raw;
+
+		struct {
+			uint16_t error_code;
+			uint16_t size;
+		};
+	} spi_rx_hdr;
+#pragma pack(pop)
+
+#ifdef SPI_V3_DEBUG_PRINT
+	NT_LOG(DBG, NTHW, "%s:  Started\n", __func__);
+#endif
+
+	/* Disable transmission from Tx FIFO */
+	result = nthw_spim_enable(p->mp_spim_mod, false);
+
+	if (result != 0) {
+		NT_LOG(WRN, NTHW, "nthw_spim_enable failed\n");
+		return result;
+	}
+
+	/* Enable SPIS module */
+	result = nthw_spis_enable(p->mp_spis_mod, true);
+
+	if (result != 0) {
+		NT_LOG(WRN, NTHW, "nthw_spis_enable failed\n");
+		return result;
+	}
+
+	/* Put data into Tx FIFO */
+	spi_tx_hdr.opcode = opcode;
+	spi_tx_hdr.size = tx_buf->size;
+
+#ifdef SPI_V3_DEBUG_PRINT
+	NT_LOG(DBG, NTHW, "Opcode=0x%04X tx_bufSize=0x%04X rx_bufSize=0x%04X\n", opcode,
+		tx_buf->size, rx_buf->size);
+
+#endif	/* SPI_V3_DEBUG_PRINT */
+
+	result = nthw_spim_write_tx_fifo(p->mp_spim_mod, htonl(spi_tx_hdr.raw));
+
+	if (result != 0) {
+		NT_LOG(WRN, NTHW, "nthw_spim_write_tx_fifo failed\n");
+		return result;
+	}
+
+	{
+		uint8_t *tx_data = (uint8_t *)tx_buf->p_buf;
+		uint16_t tx_size = tx_buf->size;
+		uint16_t count;
+		uint32_t value;
+
+		while (tx_size > 0) {
+			if (tx_size > 4) {
+				count = 4;
+
+			} else {
+				count = tx_size;
+				value = 0;
+			}
+
+			memcpy(&value, tx_data, count);
+
+			result = nthw_spim_write_tx_fifo(p->mp_spim_mod, htonl(value));
+
+			if (result != 0) {
+				NT_LOG(WRN, NTHW, "nthw_spim_write_tx_fifo failed\n");
+				return result;
+			}
+
+			tx_size = (uint16_t)(tx_size - count);
+			tx_data += count;
+		}
+	}
+
+	/* Enable Tx FIFO */
+	result = nthw_spim_enable(p->mp_spim_mod, true);
+
+	if (result != 0) {
+		NT_LOG(WRN, NTHW, "nthw_spim_enable failed\n");
+		return result;
+	}
+
+	result = wait_for_tx_data_sent(p->mp_spim_mod, p->m_time_out);
+
+	if (result != 0)
+		return result;
+
+#ifdef SPI_V3_DEBUG_PRINT
+	NT_LOG(DBG, NTHW, "%s: SPI header and payload data have been sent\n", __func__);
+#endif
+
+	{
+		/* Start receiving data */
+		uint16_t rx_size =
+			sizeof(spi_rx_hdr.raw);	/* The first data to read is the header */
+		uint8_t *rx_data = (uint8_t *)rx_buf->p_buf;
+		bool rx_hdr_read = false;
+
+		rx_buf->size = 0;
+
+		while (true) {
+			uint16_t count;
+			uint32_t value;
+
+			if (!rx_hdr_read) {	/* Read the header */
+				result = wait_for_rx_data_ready(p->mp_spis_mod, p->m_time_out);
+
+				if (result != 0)
+					return result;
+
+				result = nthw_spis_read_rx_fifo(p->mp_spis_mod, &spi_rx_hdr.raw);
+
+				if (result != 0) {
+					NT_LOG(WRN, NTHW, "nthw_spis_read_rx_fifo failed\n");
+					return result;
+				}
+
+				spi_rx_hdr.raw = ntohl(spi_rx_hdr.raw);
+				rx_size = spi_rx_hdr.size;
+				rx_hdr_read = true;	/* Next time read payload */
+
+#ifdef SPI_V3_DEBUG_PRINT
+				NT_LOG(DBG, NTHW,
+					"  spi_rx_hdr.error_code = 0x%04X, spi_rx_hdr.size = 0x%04X\n",
+					spi_rx_hdr.error_code, spi_rx_hdr.size);
+#endif
+
+				if (spi_rx_hdr.error_code != 0) {
+					result = -1;	/* NT_ERROR_AVR_OPCODE_RETURNED_ERROR; */
+					break;
+				}
+
+				if (rx_size > max_payload_rx_size) {
+					result = 1;	/* NT_ERROR_AVR_RX_BUFFER_TOO_SMALL; */
+					break;
+				}
+
+			} else {/* Read the payload */
+				count = (uint16_t)(rx_size < 4U ? rx_size : 4U);
+
+				if (count == 0)
+					break;
+
+				result = wait_for_rx_data_ready(p->mp_spis_mod, p->m_time_out);
+
+				if (result != 0)
+					return result;
+
+				result = nthw_spis_read_rx_fifo(p->mp_spis_mod, &value);
+
+				if (result != 0) {
+					NT_LOG(WRN, NTHW, "nthw_spis_read_rx_fifo failed\n");
+					return result;
+				}
+
+				value = ntohl(value);	/* Convert to host endian */
+				memcpy(rx_data, &value, count);
+				rx_buf->size = (uint16_t)(rx_buf->size + count);
+				rx_size = (uint16_t)(rx_size - count);
+				rx_data += count;
+			}
+		}
+	}
+
+#ifdef SPI_V3_DEBUG_PRINT
+	NT_LOG(DBG, NTHW, "  RxData: %d\n", rx_buf->size);
+	dump_hex(rx_buf->p_buf, rx_buf->size);
+	NT_LOG(DBG, NTHW, "%s:  Ended: %d\n", __func__, result);
+#endif
+
+	return result;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_spim.c b/drivers/net/ntnic/nthw/core/nthw_spim.c
new file mode 100644
index 0000000000..ffe4330472
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spim.c
@@ -0,0 +1,121 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_spim.h"
+
+nthw_spim_t *nthw_spim_new(void)
+{
+	nthw_spim_t *p = malloc(sizeof(nthw_spim_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_spim_t));
+
+	return p;
+}
+
+int nthw_spim_init(nthw_spim_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_SPIM, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: SPIM %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_spim = mod;
+
+	/* SPIM is a primary communication channel - turn off debug by default */
+	nthw_module_set_debug_mode(p->mp_mod_spim, 0x00);
+
+	p->mp_reg_srr = nthw_module_get_register(p->mp_mod_spim, SPIM_SRR);
+	p->mp_fld_srr_rst = nthw_register_get_field(p->mp_reg_srr, SPIM_SRR_RST);
+
+	p->mp_reg_cr = nthw_module_get_register(p->mp_mod_spim, SPIM_CR);
+	p->mp_fld_cr_loop = nthw_register_get_field(p->mp_reg_cr, SPIM_CR_LOOP);
+	p->mp_fld_cr_en = nthw_register_get_field(p->mp_reg_cr, SPIM_CR_EN);
+	p->mp_fld_cr_txrst = nthw_register_get_field(p->mp_reg_cr, SPIM_CR_TXRST);
+	p->mp_fld_cr_rxrst = nthw_register_get_field(p->mp_reg_cr, SPIM_CR_RXRST);
+
+	p->mp_reg_sr = nthw_module_get_register(p->mp_mod_spim, SPIM_SR);
+	p->mp_fld_sr_done = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_DONE);
+	p->mp_fld_sr_txempty = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_TXEMPTY);
+	p->mp_fld_sr_rxempty = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_RXEMPTY);
+	p->mp_fld_sr_txfull = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_TXFULL);
+	p->mp_fld_sr_rxfull = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_RXFULL);
+	p->mp_fld_sr_txlvl = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_TXLVL);
+	p->mp_fld_sr_rxlvl = nthw_register_get_field(p->mp_reg_sr, SPIM_SR_RXLVL);
+
+	p->mp_reg_dtr = nthw_module_get_register(p->mp_mod_spim, SPIM_DTR);
+	p->mp_fld_dtr_dtr = nthw_register_get_field(p->mp_reg_dtr, SPIM_DTR_DTR);
+
+	p->mp_reg_drr = nthw_module_get_register(p->mp_mod_spim, SPIM_DRR);
+	p->mp_fld_drr_drr = nthw_register_get_field(p->mp_reg_drr, SPIM_DRR_DRR);
+
+	p->mp_reg_cfg = nthw_module_get_register(p->mp_mod_spim, SPIM_CFG);
+	p->mp_fld_cfg_pre = nthw_register_get_field(p->mp_reg_cfg, SPIM_CFG_PRE);
+
+	p->mp_reg_cfg_clk = nthw_module_query_register(p->mp_mod_spim, SPIM_CFG_CLK);
+	p->mp_fld_cfg_clk_mode = nthw_register_query_field(p->mp_reg_cfg, SPIM_CFG_CLK_MODE);
+
+	return 0;
+}
+
+void nthw_spim_delete(nthw_spim_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_spim_t));
+		free(p);
+	}
+}
+
+uint32_t nthw_spim_reset(nthw_spim_t *p)
+{
+	nthw_register_update(p->mp_reg_srr);
+	nthw_field_set_val32(p->mp_fld_srr_rst, 0x0A);	/* 0x0A hardcoded value - see doc */
+	nthw_register_flush(p->mp_reg_srr, 1);
+
+	return 0;
+}
+
+uint32_t nthw_spim_enable(nthw_spim_t *p, bool b_enable)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+
+	if (b_enable)
+		nthw_field_set_all(p->mp_fld_cr_en);
+
+	else
+		nthw_field_clr_all(p->mp_fld_cr_en);
+
+	nthw_field_flush_register(p->mp_fld_cr_en);
+
+	return 0;
+}
+
+uint32_t nthw_spim_write_tx_fifo(nthw_spim_t *p, uint32_t n_data)
+{
+	nthw_field_set_val_flush32(p->mp_fld_dtr_dtr, n_data);
+	return 0;
+}
+
+uint32_t nthw_spim_get_tx_fifo_empty(nthw_spim_t *p, bool *pb_empty)
+{
+	assert(pb_empty);
+
+	*pb_empty = nthw_field_get_updated(p->mp_fld_sr_txempty) ? true : false;
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_spis.c b/drivers/net/ntnic/nthw/core/nthw_spis.c
new file mode 100644
index 0000000000..2915d71bf9
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spis.c
@@ -0,0 +1,129 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_spis.h"
+
+nthw_spis_t *nthw_spis_new(void)
+{
+	nthw_spis_t *p = malloc(sizeof(nthw_spis_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_spis_t));
+
+	return p;
+}
+
+int nthw_spis_init(nthw_spis_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_SPIS, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: SPIS %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_spis = mod;
+
+	/* SPIS is a primary communication channel - turn off debug by default */
+	nthw_module_set_debug_mode(p->mp_mod_spis, 0x00);
+
+	p->mp_reg_srr = nthw_module_get_register(p->mp_mod_spis, SPIS_SRR);
+	p->mp_fld_srr_rst = nthw_register_get_field(p->mp_reg_srr, SPIS_SRR_RST);
+
+	p->mp_reg_cr = nthw_module_get_register(p->mp_mod_spis, SPIS_CR);
+	p->mp_fld_cr_loop = nthw_register_get_field(p->mp_reg_cr, SPIS_CR_LOOP);
+	p->mp_fld_cr_en = nthw_register_get_field(p->mp_reg_cr, SPIS_CR_EN);
+	p->mp_fld_cr_txrst = nthw_register_get_field(p->mp_reg_cr, SPIS_CR_TXRST);
+	p->mp_fld_cr_rxrst = nthw_register_get_field(p->mp_reg_cr, SPIS_CR_RXRST);
+	p->mp_fld_cr_debug = nthw_register_get_field(p->mp_reg_cr, SPIS_CR_DEBUG);
+
+	p->mp_reg_sr = nthw_module_get_register(p->mp_mod_spis, SPIS_SR);
+	p->mp_fld_sr_done = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_DONE);
+	p->mp_fld_sr_txempty = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_TXEMPTY);
+	p->mp_fld_sr_rxempty = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_RXEMPTY);
+	p->mp_fld_sr_txfull = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_TXFULL);
+	p->mp_fld_sr_rxfull = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_RXFULL);
+	p->mp_fld_sr_txlvl = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_TXLVL);
+	p->mp_fld_sr_rxlvl = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_RXLVL);
+	p->mp_fld_sr_frame_err = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_FRAME_ERR);
+	p->mp_fld_sr_read_err = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_READ_ERR);
+	p->mp_fld_sr_write_err = nthw_register_get_field(p->mp_reg_sr, SPIS_SR_WRITE_ERR);
+
+	p->mp_reg_dtr = nthw_module_get_register(p->mp_mod_spis, SPIS_DTR);
+	p->mp_fld_dtr_dtr = nthw_register_get_field(p->mp_reg_dtr, SPIS_DTR_DTR);
+
+	p->mp_reg_drr = nthw_module_get_register(p->mp_mod_spis, SPIS_DRR);
+	p->mp_fld_drr_drr = nthw_register_get_field(p->mp_reg_drr, SPIS_DRR_DRR);
+
+	p->mp_reg_ram_ctrl = nthw_module_get_register(p->mp_mod_spis, SPIS_RAM_CTRL);
+	p->mp_fld_ram_ctrl_adr = nthw_register_get_field(p->mp_reg_ram_ctrl, SPIS_RAM_CTRL_ADR);
+	p->mp_fld_ram_ctrl_cnt = nthw_register_get_field(p->mp_reg_ram_ctrl, SPIS_RAM_CTRL_CNT);
+
+	p->mp_reg_ram_data = nthw_module_get_register(p->mp_mod_spis, SPIS_RAM_DATA);
+	p->mp_fld_ram_data_data = nthw_register_get_field(p->mp_reg_ram_data, SPIS_RAM_DATA_DATA);
+
+	return 0;
+}
+
+void nthw_spis_delete(nthw_spis_t *p)
+{
+	if (p) {
+		memset(p, 0, sizeof(nthw_spis_t));
+		free(p);
+	}
+}
+
+uint32_t nthw_spis_reset(nthw_spis_t *p)
+{
+	nthw_register_update(p->mp_reg_srr);
+	nthw_field_set_val32(p->mp_fld_srr_rst, 0x0A);	/* 0x0A hardcoded value - see doc */
+	nthw_register_flush(p->mp_reg_srr, 1);
+
+	return 0;
+}
+
+uint32_t nthw_spis_enable(nthw_spis_t *p, bool b_enable)
+{
+	nthw_field_update_register(p->mp_fld_cr_en);
+
+	if (b_enable)
+		nthw_field_set_all(p->mp_fld_cr_en);
+
+	else
+		nthw_field_clr_all(p->mp_fld_cr_en);
+
+	nthw_field_flush_register(p->mp_fld_cr_en);
+
+	return 0;
+}
+
+uint32_t nthw_spis_get_rx_fifo_empty(nthw_spis_t *p, bool *pb_empty)
+{
+	assert(pb_empty);
+
+	*pb_empty = nthw_field_get_updated(p->mp_fld_sr_rxempty) ? true : false;
+
+	return 0;
+}
+
+uint32_t nthw_spis_read_rx_fifo(nthw_spis_t *p, uint32_t *p_data)
+{
+	assert(p_data);
+
+	*p_data = nthw_field_get_updated(p->mp_fld_drr_drr);
+
+	return 0;
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_tsm.c b/drivers/net/ntnic/nthw/core/nthw_tsm.c
new file mode 100644
index 0000000000..e0bf61652d
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_tsm.c
@@ -0,0 +1,167 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_tsm.h"
+
+nthw_tsm_t *nthw_tsm_new(void)
+{
+	nthw_tsm_t *p = malloc(sizeof(nthw_tsm_t));
+
+	if (p)
+		memset(p, 0, sizeof(nthw_tsm_t));
+
+	return p;
+}
+
+int nthw_tsm_init(nthw_tsm_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+	const char *const p_adapter_id_str = p_fpga->p_fpga_info->mp_adapter_id_str;
+	nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_TSM, n_instance);
+
+	if (p == NULL)
+		return mod == NULL ? -1 : 0;
+
+	if (mod == NULL) {
+		NT_LOG(ERR, NTHW, "%s: TSM %d: no such instance\n", p_adapter_id_str, n_instance);
+		return -1;
+	}
+
+	p->mp_fpga = p_fpga;
+	p->mn_instance = n_instance;
+	p->mp_mod_tsm = mod;
+
+	{
+		nthw_register_t *p_reg;
+
+		p_reg = nthw_module_get_register(p->mp_mod_tsm, TSM_CONFIG);
+		p->mp_fld_config_ts_format = nthw_register_get_field(p_reg, TSM_CONFIG_TS_FORMAT);
+
+		p_reg = nthw_module_get_register(p->mp_mod_tsm, TSM_TIMER_CTRL);
+		p->mp_fld_timer_ctrl_timer_en_t0 =
+			nthw_register_get_field(p_reg, TSM_TIMER_CTRL_TIMER_EN_T0);
+		p->mp_fld_timer_ctrl_timer_en_t1 =
+			nthw_register_get_field(p_reg, TSM_TIMER_CTRL_TIMER_EN_T1);
+
+		p_reg = nthw_module_get_register(p->mp_mod_tsm, TSM_TIMER_T0);
+		p->mp_fld_timer_timer_t0_max_count =
+			nthw_register_get_field(p_reg, TSM_TIMER_T0_MAX_COUNT);
+
+		p_reg = nthw_module_get_register(p->mp_mod_tsm, TSM_TIMER_T1);
+		p->mp_fld_timer_timer_t1_max_count =
+			nthw_register_get_field(p_reg, TSM_TIMER_T1_MAX_COUNT);
+
+		p->mp_reg_time_lo = nthw_module_get_register(p->mp_mod_tsm, TSM_TIME_LO);
+		p_reg = p->mp_reg_time_lo;
+		p->mp_fld_time_lo = nthw_register_get_field(p_reg, TSM_TIME_LO_NS);
+
+		p->mp_reg_time_hi = nthw_module_get_register(p->mp_mod_tsm, TSM_TIME_HI);
+		p_reg = p->mp_reg_time_hi;
+		p->mp_fld_time_hi = nthw_register_get_field(p_reg, TSM_TIME_HI_SEC);
+
+		p->mp_reg_ts_lo = nthw_module_get_register(p->mp_mod_tsm, TSM_TS_LO);
+		p_reg = p->mp_reg_ts_lo;
+		p->mp_fld_ts_lo = nthw_register_get_field(p_reg, TSM_TS_LO_TIME);
+
+		p->mp_reg_ts_hi = nthw_module_get_register(p->mp_mod_tsm, TSM_TS_HI);
+		p_reg = p->mp_reg_ts_hi;
+		p->mp_fld_ts_hi = nthw_register_get_field(p_reg, TSM_TS_HI_TIME);
+	}
+	return 0;
+}
+
+int nthw_tsm_get_ts(nthw_tsm_t *p, uint64_t *p_ts)
+{
+	uint32_t n_ts_lo, n_ts_hi;
+	uint64_t val;
+
+	if (!p_ts)
+		return -1;
+
+	n_ts_lo = nthw_field_get_updated(p->mp_fld_ts_lo);
+	n_ts_hi = nthw_field_get_updated(p->mp_fld_ts_hi);
+
+	val = ((((uint64_t)n_ts_hi) << 32UL) | n_ts_lo);
+
+	if (p_ts)
+		*p_ts = val;
+
+	return 0;
+}
+
+int nthw_tsm_get_time(nthw_tsm_t *p, uint64_t *p_time)
+{
+	uint32_t n_time_lo, n_time_hi;
+	uint64_t val;
+
+	if (!p_time)
+		return -1;
+
+	n_time_lo = nthw_field_get_updated(p->mp_fld_time_lo);
+	n_time_hi = nthw_field_get_updated(p->mp_fld_time_hi);
+
+	val = ((((uint64_t)n_time_hi) << 32UL) | n_time_lo);
+
+	if (p_time)
+		*p_time = val;
+
+	return 0;
+}
+
+int nthw_tsm_set_timer_t0_enable(nthw_tsm_t *p, bool b_enable)
+{
+	nthw_field_update_register(p->mp_fld_timer_ctrl_timer_en_t0);
+
+	if (b_enable)
+		nthw_field_set_flush(p->mp_fld_timer_ctrl_timer_en_t0);
+
+	else
+		nthw_field_clr_flush(p->mp_fld_timer_ctrl_timer_en_t0);
+
+	return 0;
+}
+
+int nthw_tsm_set_timer_t0_max_count(nthw_tsm_t *p, uint32_t n_timer_val)
+{
+	/* Timer T0 - stat toggle timer */
+	nthw_field_update_register(p->mp_fld_timer_timer_t0_max_count);
+	nthw_field_set_val_flush32(p->mp_fld_timer_timer_t0_max_count,
+		n_timer_val);	/* ns (50*1000*1000) */
+	return 0;
+}
+
+int nthw_tsm_set_timer_t1_enable(nthw_tsm_t *p, bool b_enable)
+{
+	nthw_field_update_register(p->mp_fld_timer_ctrl_timer_en_t1);
+
+	if (b_enable)
+		nthw_field_set_flush(p->mp_fld_timer_ctrl_timer_en_t1);
+
+	else
+		nthw_field_clr_flush(p->mp_fld_timer_ctrl_timer_en_t1);
+
+	return 0;
+}
+
+int nthw_tsm_set_timer_t1_max_count(nthw_tsm_t *p, uint32_t n_timer_val)
+{
+	/* Timer T1 - keep alive timer */
+	nthw_field_update_register(p->mp_fld_timer_timer_t1_max_count);
+	nthw_field_set_val_flush32(p->mp_fld_timer_timer_t1_max_count,
+		n_timer_val);	/* ns (100*1000*1000) */
+	return 0;
+}
+
+int nthw_tsm_set_config_ts_format(nthw_tsm_t *p, uint32_t n_val)
+{
+	nthw_field_update_register(p->mp_fld_config_ts_format);
+	/* 0x1: Native - 10ns units, start date: 1970-01-01. */
+	nthw_field_set_val_flush32(p->mp_fld_config_ts_format, n_val);
+	return 0;
+}
-- 
2.44.0


  parent reply	other threads:[~2024-05-31 15:50 UTC|newest]

Thread overview: 101+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-30 14:48 [PATCH v1 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-05-30 14:48 ` [PATCH v1 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 07/17] net/ntnic: add API " Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 12/17] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-05-30 14:49 ` [PATCH v1 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-05-31 15:47 ` [PATCH v2 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 07/17] net/ntnic: add API " Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-05-31 15:47   ` Serhii Iliushyk [this message]
2024-05-31 15:47   ` [PATCH v2 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-05-31 15:47   ` [PATCH v2 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-06-03 16:17 ` [PATCH v3 01/17] net/ntnic: Add registers for NapaTech SmartNiC Serhii Iliushyk
2024-06-03 16:17   ` [PATCH v3 02/17] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 03/17] net/ntnic: add interfaces for " Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 04/17] net/ntnic: add FPGA model implementation Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 05/17] net/ntnic: add NTNIC adapter interfaces Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 06/17] net/ntnic: add interfaces for PMD driver modules Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 07/17] net/ntnic: add API " Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 08/17] net/ntnic: add interfaces for flow API engine Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 09/17] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 10/17] net/ntnic: add Logs and utilities implementation Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 11/17] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 12/17] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 13/17] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 14/17] net/ntnic: add adapter initialization API Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 15/17] net/ntnic: add link management module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 16/17] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-03 16:18   ` [PATCH v3 17/17] net/ntnic: add NIM module Serhii Iliushyk
2024-06-04 10:29   ` [PATCH v3 01/17] net/ntnic: Add registers for NapaTech SmartNiC Mykola Kostenok
2024-06-07 13:03     ` Serhii Iliushyk
2024-06-12  8:50       ` Ferruh Yigit
2024-06-12  8:55         ` Ferruh Yigit
2024-06-26 19:55 ` [PATCH v4 01/23] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 02/23] net/ntnic: add logging implementation Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 03/23] net/ntnic: add minimal initialization for PCI device Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 04/23] net/ntnic: add NT utilities implementation Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 05/23] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 06/23] net/ntnic: add NT NIC driver dependencies Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 07/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 08/23] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 09/23] net/ntnic: add registers and FPGA model for NapaTech NIC Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 10/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 11/23] net/ntnic: add FPGA initialization functionality Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 12/23] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 13/23] net/ntnic: add reset module for " Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 14/23] net/ntnic: add clock profiles " Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 15/23] net/ntnic: add MAC and packet features Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 16/23] net/ntnic: add link management module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 17/23] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 18/23] net/ntnic: add NIM module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 19/23] net/ntnic: add QSFP support Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 20/23] net/ntnic: add QSFP28 support Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 21/23] net/ntnic: add GPIO PHY module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 22/23] net/ntnic: add MAC PCS register interface module Serhii Iliushyk
2024-06-26 19:55   ` [PATCH v4 23/23] net/ntnic: add GMF (Generic MAC Feeder) module Serhii Iliushyk
2024-06-27  7:38 ` [PATCH v5 01/23] net/ntnic: add ethdev and makes PMD available Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 02/23] net/ntnic: add logging implementation Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 03/23] net/ntnic: add minimal initialization for PCI device Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 04/23] net/ntnic: add NT utilities implementation Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 05/23] net/ntnic: add VFIO module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 06/23] net/ntnic: add NT NIC driver dependencies Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 07/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 08/23] net/ntnic: add adapter initialization Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 09/23] net/ntnic: add registers and FPGA model for NapaTech NIC Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 10/23] net/ntnic: add core platform functionality Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 11/23] net/ntnic: add FPGA initialization functionality Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 12/23] net/ntnic: add support of the NT200A0X smartNIC Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 13/23] net/ntnic: add reset module for " Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 14/23] net/ntnic: add clock profiles " Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 15/23] net/ntnic: add MAC and packet features Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 16/23] net/ntnic: add link management module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 17/23] net/ntnic: add link 100G module Serhii Iliushyk
2024-06-27  7:38   ` [PATCH v5 18/23] net/ntnic: add NIM module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 19/23] net/ntnic: add QSFP support Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 20/23] net/ntnic: add QSFP28 support Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 21/23] net/ntnic: add GPIO PHY module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 22/23] net/ntnic: add MAC PCS register interface module Serhii Iliushyk
2024-06-27  7:39   ` [PATCH v5 23/23] net/ntnic: add GMF (Generic MAC Feeder) module Serhii Iliushyk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240531154731.1856874-12-sil-plv@napatech.com \
    --to=sil-plv@napatech.com \
    --cc=andrew.rybchenko@oktetlabs.ru \
    --cc=ckm@napatech.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=mko-plv@napatech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).