From: Danylo Vodopianov <dvo-...@napatech.com>

Initialize NIM and 100G port for Agilex FPGA

Signed-off-by: Danylo Vodopianov <dvo-...@napatech.com>
---
 .../link_agx_100g/nt4ga_agx_link_100g.c       | 143 ++++++++++++++++++
 drivers/net/ntnic/meson.build                 |   1 +
 .../net/ntnic/nthw/core/include/nthw_gmf.h    |   2 +
 .../ntnic/nthw/core/include/nthw_pcal6416a.h  |  10 ++
 drivers/net/ntnic/nthw/core/nthw_gmf.c        |  41 +++++
 drivers/net/ntnic/nthw/core/nthw_pcal6416a.c  |  41 +++++
 6 files changed, 238 insertions(+)
 create mode 100644 drivers/net/ntnic/nthw/core/nthw_pcal6416a.c

diff --git a/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c 
b/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
index 9551dfdfdc..6593c90ca5 100644
--- a/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
+++ b/drivers/net/ntnic/link_mgmt/link_agx_100g/nt4ga_agx_link_100g.c
@@ -197,6 +197,26 @@ static int phy_set_line_loopback(adapter_info_t *drv, int 
port, loopback_line_t
        return 0;
 }
 
+/*
+ * Nim handling
+ */
+
+static bool nim_is_present(nim_i2c_ctx_p ctx, uint8_t nim_idx)
+{
+       assert(nim_idx < NUM_ADAPTER_PORTS_MAX);
+
+       nthw_pcal6416a_t *p = ctx->hwagx.p_io_nim;
+       uint8_t data = 0;
+
+       if (nim_idx == 0)
+               nthw_pcal6416a_read(p, 3, &data);
+
+       else if (nim_idx == 1)
+               nthw_pcal6416a_read(p, 7, &data);
+
+       return data == 0;
+}
+
 /*
  * Utility functions
  */
@@ -295,6 +315,119 @@ set_loopback(struct adapter_info_s *p_adapter_info, int 
port, uint32_t mode, uin
        nt_os_wait_usec(10000); /* 10ms - arbitrary choice */
 }
 
+/*
+ * Initialize NIM, Code based on nt400d1x.cpp: MyPort::createNim()
+ */
+
+static int create_nim(adapter_info_t *drv, int port, bool enable)
+{
+       int res = 0;
+       const uint8_t valid_nim_id = NT_NIM_QSFP28;
+       sfp_nim_state_t nim;
+       nt4ga_link_t *link_info = &drv->nt4ga_link;
+       nim_i2c_ctx_t *nim_ctx = &link_info->u.nim_ctx[port];
+
+       assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
+       assert(link_info->variables_initialized);
+
+       if (!enable) {
+               phy_reset_rx(drv, port);
+               phy_reset_tx(drv, port);
+       }
+
+       /*
+        * Wait a little after a module has been inserted before trying to 
access I2C
+        * data, otherwise the module will not respond correctly.
+        */
+       nt_os_wait_usec(1000000);       /* pause 1.0s */
+
+       res = construct_and_preinit_nim(nim_ctx, NULL);
+
+       if (res)
+               return res;
+
+       res = nim_state_build(nim_ctx, &nim);
+
+       if (res)
+               return res;
+
+       /* Set FEC to be enabled by default */
+       nim_ctx->specific_u.qsfp.specific_u.qsfp28.media_side_fec_ena = true;
+
+       NT_LOG(DBG, NTHW, "%s: NIM id = %u (%s), br = %u, vendor = '%s', pn = 
'%s', sn='%s'",
+               drv->mp_port_id_str[port], nim_ctx->nim_id, 
nim_id_to_text(nim_ctx->nim_id), nim.br,
+               nim_ctx->vendor_name, nim_ctx->prod_no, nim_ctx->serial_no);
+
+       /*
+        * Does the driver support the NIM module type?
+        */
+       if (nim_ctx->nim_id != valid_nim_id) {
+               NT_LOG(ERR, NTHW, "%s: The driver does not support the NIM 
module type %s",
+                       drv->mp_port_id_str[port], 
nim_id_to_text(nim_ctx->nim_id));
+               NT_LOG(DBG, NTHW, "%s: The driver supports the NIM module type 
%s",
+                       drv->mp_port_id_str[port], 
nim_id_to_text(valid_nim_id));
+               return -1;
+       }
+
+       return res;
+}
+
+/*
+ * Initialize one 100 Gbps port.
+ */
+static int _port_init(adapter_info_t *p_info, nthw_fpga_t *fpga, int port)
+{
+       uint8_t adapter_no = p_info->adapter_no;
+       int res;
+
+       nt4ga_link_t *link_info = &p_info->nt4ga_link;
+       nthw_gfg_t *p_gfg = &link_info->u.var_a100g.gfg[adapter_no];
+       nthw_phy_tile_t *p_phy_tile = p_info->fpga_info.mp_nthw_agx.p_phy_tile;
+       nthw_rpf_t *p_rpf = p_info->fpga_info.mp_nthw_agx.p_rpf;
+
+       assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
+       assert(link_info->variables_initialized);
+
+       link_info->link_info[port].link_speed = NT_LINK_SPEED_100G;
+       link_info->link_info[port].link_duplex = NT_LINK_DUPLEX_FULL;
+       link_info->link_info[port].link_auto_neg = NT_LINK_AUTONEG_OFF;
+       link_info->speed_capa |= NT_LINK_SPEED_100G;
+
+       nthw_gfg_stop(p_gfg, port);
+
+       for (uint8_t lane = 0; lane < 4; lane++)
+               nthw_phy_tile_set_host_loopback(p_phy_tile, port, lane, false);
+
+       swap_tx_rx_polarity(p_info, port, true);
+       nthw_rpf_set_ts_at_eof(p_rpf, true);
+
+       NT_LOG(DBG, NTNIC, "%s: Setting up port %d", 
p_info->mp_port_id_str[port], port);
+
+       phy_reset_rx(p_info, port);
+
+       if (nthw_gmf_init(NULL, fpga, port) == 0) {
+               nthw_gmf_t gmf;
+
+               if (nthw_gmf_init(&gmf, fpga, port) == 0)
+                       nthw_gmf_set_enable_tsi(&gmf, true, 0, 0, false);
+       }
+
+       nthw_rpf_unblock(p_rpf);
+
+       res = create_nim(p_info, port, true);
+
+       if (res) {
+               NT_LOG(WRN, NTNIC, "%s: NIM initialization failed",
+                       p_info->mp_port_id_str[port]);
+               return res;
+       }
+
+       NT_LOG(DBG, NTNIC, "%s: NIM initialized", p_info->mp_port_id_str[port]);
+
+       phy_reset_rx(p_info, port);
+       return res;
+}
+
 /*
  * Link state machine
  */
@@ -310,6 +443,7 @@ static void *_common_ptp_nim_state_machine(void *data)
        /* link_state_t new_link_state; */
 
        link_state_t *link_state = link_info->link_state;
+       nim_i2c_ctx_t *nim_ctx = link_info->u.var_a100g.nim_ctx;
 
        if (!fpga) {
                NT_LOG(ERR, NTNIC, "%s: fpga is NULL", drv->mp_adapter_id_str);
@@ -361,6 +495,15 @@ static void *_common_ptp_nim_state_machine(void *data)
                                continue;
 
                        if (link_info->port_action[i].port_lpbk_mode != 
last_lpbk_mode[i]) {
+                               /* Loopback mode has changed. Do something */
+                               if (!nim_is_present(&nim_ctx[i], i)) {
+                                       /*
+                                        * If there is no Nim present, we need 
to initialize the
+                                        * port  anyway
+                                        */
+                                       _port_init(drv, fpga, i);
+                               }
+
                                set_loopback(drv,
                                        i,
                                        
link_info->port_action[i].port_lpbk_mode,
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 271115cdd3..b1505c5549 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -55,6 +55,7 @@ sources = files(
         'nthw/core/nthw_iic.c',
         'nthw/core/nthw_mac_pcs.c',
         'nthw/core/nthw_pcie3.c',
+        'nthw/core/nthw_pcal6416a.c',
         'nthw/core/nthw_phy_tile.c',
         'nthw/core/nthw_si5332_si5156.c',
         'nthw/core/nthw_rpf.c',
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_gmf.h 
b/drivers/net/ntnic/nthw/core/include/nthw_gmf.h
index cc5be85154..c8beb2117c 100644
--- a/drivers/net/ntnic/nthw/core/include/nthw_gmf.h
+++ b/drivers/net/ntnic/nthw/core/include/nthw_gmf.h
@@ -58,6 +58,8 @@ struct nthw_gmf {
 typedef struct nthw_gmf nthw_gmf_t;
 
 int nthw_gmf_init(nthw_gmf_t *p, nthw_fpga_t *p_fpga, int n_instance);
+void nthw_gmf_set_enable_tsi(nthw_gmf_t *p, bool enable, int 
tsi_dynamic_offset,
+       int tsi_static_offset, bool tsi_always);
 
 void nthw_gmf_set_enable(nthw_gmf_t *p, bool enable);
 
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_pcal6416a.h 
b/drivers/net/ntnic/nthw/core/include/nthw_pcal6416a.h
index 636d2beb85..5ef14a0bc9 100644
--- a/drivers/net/ntnic/nthw/core/include/nthw_pcal6416a.h
+++ b/drivers/net/ntnic/nthw/core/include/nthw_pcal6416a.h
@@ -7,13 +7,23 @@
 
 #include <stdint.h>
 
+#include "nthw_i2cm.h"
+#include "nthw_si5332_si5156.h"
+
 /*
  * PCAL6416A I/O expander class
  */
 
 struct nthw_pcal6416a {
+       nthw_i2cm_t *mp_nt_i2cm;
+       uint8_t m_dev_address;
+       nthw_pca9849_t *mp_ca9849;
+       uint8_t m_mux_channel;
+       uint8_t m_config_data[2];
 };
 
 typedef struct nthw_pcal6416a nthw_pcal6416a_t;
 
+void nthw_pcal6416a_read(nthw_pcal6416a_t *p, uint8_t pin, uint8_t *value);
+
 #endif /* __NTHW_PCAL6416A_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nthw_gmf.c 
b/drivers/net/ntnic/nthw/core/nthw_gmf.c
index 16a4c288bd..9fb708bc50 100644
--- a/drivers/net/ntnic/nthw/core/nthw_gmf.c
+++ b/drivers/net/ntnic/nthw/core/nthw_gmf.c
@@ -131,3 +131,44 @@ void nthw_gmf_set_enable(nthw_gmf_t *p, bool enable)
        if (!p->m_administrative_block)
                nthw_field_set_val_flush32(p->mp_ctrl_enable, enable ? 1 : 0);
 }
+
+void nthw_gmf_set_enable_tsi(nthw_gmf_t *p, bool enable, int 
tsi_dynamic_offset,
+       int tsi_static_offset, bool tsi_always)
+{
+       if (!p->m_administrative_block) {
+               nthw_field_update_register(p->mp_ctrl_enable);
+
+               if (p->mp_ctrl_ts_inject_always) {
+                       /*
+                        * Do not force timestamp Inject- let the TBH control 
this now
+                        * Later we could consider an ini-setting for 
controlling this
+                        */
+                       nthw_field_set_val_flush32(p->mp_ctrl_ts_inject_always,
+                               tsi_always ? 1 : 0);
+               }
+
+               if (p->mp_ctrl_fcs_always) {
+                       /*
+                        * Do not force FSC calculation - let the TBH control 
this
+                        * Later we could consider an ini-setting for 
controlling this
+                        */
+                       nthw_field_set_val_flush32(p->mp_ctrl_fcs_always, 0);
+               }
+
+               if (p->mp_ts_inject) {
+                       nthw_register_update(p->mp_ts_inject);
+
+                       if (p->mp_ts_inject_pos) {
+                               nthw_field_set_val_flush32(p->mp_ts_inject_pos,
+                                       (uint32_t)tsi_dynamic_offset);
+                       }
+
+                       if (p->mp_ts_inject_offset) {
+                               
nthw_field_set_val_flush32(p->mp_ts_inject_offset,
+                                       (uint32_t)tsi_static_offset);
+                       }
+               }
+
+               nthw_field_set_val_flush32(p->mp_ctrl_enable, enable ? 1 : 0);
+       }
+}
diff --git a/drivers/net/ntnic/nthw/core/nthw_pcal6416a.c 
b/drivers/net/ntnic/nthw/core/nthw_pcal6416a.c
new file mode 100644
index 0000000000..37b6e7ec57
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_pcal6416a.c
@@ -0,0 +1,41 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+#include <pthread.h>
+
+#include "nt_util.h"
+#include "ntlog.h"
+
+#include "nthw_drv.h"
+#include "nthw_register.h"
+
+#include "nthw_pcal6416a.h"
+
+static const uint8_t read_port[2] = { 0x00, 0x01 };
+
+/*
+ * PCAL6416A I/O expander class
+ */
+
+void nthw_pcal6416a_read(nthw_pcal6416a_t *p, uint8_t pin, uint8_t *value)
+{
+       uint8_t port;
+       uint8_t data;
+
+       rte_spinlock_lock(&p->mp_nt_i2cm->i2cmmutex);
+       nthw_pca9849_set_channel(p->mp_ca9849, p->m_mux_channel);
+
+       if (pin < 8) {
+               port = 0;
+
+       } else {
+               port = 1;
+               pin = (uint8_t)(pin - 8);
+       }
+
+       nthw_i2cm_read(p->mp_nt_i2cm, p->m_dev_address, read_port[port], &data);
+
+       *value = (data >> pin) & 0x1;
+       rte_spinlock_unlock(&p->mp_nt_i2cm->i2cmmutex);
+}
-- 
2.45.0

Reply via email to