@@ -78,6 +78,7 @@ typedef struct port_action_s {
typedef struct adapter_100g_s {
nim_i2c_ctx_t nim_ctx[NUM_ADAPTER_PORTS_MAX]; /* Should be the first field */
+ nthw_mac_pcs_t mac_pcs100g[NUM_ADAPTER_PORTS_MAX];
nthw_gpio_phy_t gpio_phy[NUM_ADAPTER_PORTS_MAX];
} adapter_100g_t;
@@ -10,6 +10,168 @@
#include "i2c_nim.h"
#include "ntnic_mod_reg.h"
+/*
+ * Swap tx/rx polarity
+ */
+static int _swap_tx_rx_polarity(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs, int port, bool swap)
+{
+ const bool tx_polarity_swap[2][4] = { { true, true, false, false },
+ { false, true, false, false }
+ };
+ const bool rx_polarity_swap[2][4] = { { false, true, true, true },
+ { false, true, true, false }
+ };
+ uint8_t lane;
+
+ (void)drv;
+
+ for (lane = 0U; lane < 4U; lane++) {
+ if (swap) {
+ nthw_mac_pcs_swap_gty_tx_polarity(mac_pcs, lane,
+ tx_polarity_swap[port][lane]);
+ nthw_mac_pcs_swap_gty_rx_polarity(mac_pcs, lane,
+ rx_polarity_swap[port][lane]);
+
+ } else {
+ nthw_mac_pcs_swap_gty_tx_polarity(mac_pcs, lane, false);
+ nthw_mac_pcs_swap_gty_rx_polarity(mac_pcs, lane, false);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Reset RX
+ */
+static int _reset_rx(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ (void)drv;
+
+ nthw_mac_pcs_rx_path_rst(mac_pcs, true);
+ nt_os_wait_usec(10000); /* 10ms */
+ nthw_mac_pcs_rx_path_rst(mac_pcs, false);
+ nt_os_wait_usec(10000); /* 10ms */
+
+ return 0;
+}
+
+static void _set_loopback(struct adapter_info_s *p_adapter_info,
+ nthw_mac_pcs_t *mac_pcs,
+ int intf_no,
+ uint32_t mode,
+ uint32_t last_mode)
+{
+ bool swap_polerity = true;
+
+ switch (mode) {
+ case 1:
+ NT_LOG(INF, NTNIC, "%s: Applying host loopback\n",
+ p_adapter_info->mp_port_id_str[intf_no]);
+ nthw_mac_pcs_set_fec(mac_pcs, true);
+ nthw_mac_pcs_set_host_loopback(mac_pcs, true);
+ swap_polerity = false;
+ break;
+
+ case 2:
+ NT_LOG(INF, NTNIC, "%s: Applying line loopback\n",
+ p_adapter_info->mp_port_id_str[intf_no]);
+ nthw_mac_pcs_set_line_loopback(mac_pcs, true);
+ break;
+
+ default:
+ switch (last_mode) {
+ case 1:
+ NT_LOG(INF, NTNIC, "%s: Removing host loopback\n",
+ p_adapter_info->mp_port_id_str[intf_no]);
+ nthw_mac_pcs_set_host_loopback(mac_pcs, false);
+ break;
+
+ case 2:
+ NT_LOG(INF, NTNIC, "%s: Removing line loopback\n",
+ p_adapter_info->mp_port_id_str[intf_no]);
+ nthw_mac_pcs_set_line_loopback(mac_pcs, false);
+ break;
+
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ break;
+ }
+
+ if (p_adapter_info->fpga_info.nthw_hw_info.hw_id == 2 ||
+ p_adapter_info->hw_info.n_nthw_adapter_id == NT_HW_ADAPTER_ID_NT200A02) {
+ (void)_swap_tx_rx_polarity(p_adapter_info, mac_pcs, intf_no, swap_polerity);
+ }
+
+ /* After changing the loopback the system must be properly reset */
+ _reset_rx(p_adapter_info, mac_pcs);
+
+ nt_os_wait_usec(10000); /* 10ms - arbitrary choice */
+
+ if (!nthw_mac_pcs_is_rx_path_rst(mac_pcs)) {
+ nthw_mac_pcs_reset_bip_counters(mac_pcs);
+
+ if (!nthw_mac_pcs_get_fec_bypass(mac_pcs))
+ nthw_mac_pcs_reset_fec_counters(mac_pcs);
+ }
+}
+
+/*
+ * Function to retrieve the current state of a link (for one port)
+ */
+static int _link_state_build(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs,
+ nthw_gpio_phy_t *gpio_phy, int port, link_state_t *state,
+ bool is_port_disabled)
+{
+ uint32_t abs;
+ uint32_t phy_link_state;
+ uint32_t lh_abs;
+ uint32_t ll_phy_link_state;
+ uint32_t link_down_cnt;
+ uint32_t nim_interr;
+ uint32_t lh_local_fault;
+ uint32_t lh_remote_fault;
+ uint32_t lh_internal_local_fault;
+ uint32_t lh_received_local_fault;
+
+ memset(state, 0, sizeof(*state));
+ state->link_disabled = is_port_disabled;
+ nthw_mac_pcs_get_link_summary(mac_pcs, &abs, &phy_link_state, &lh_abs, &ll_phy_link_state,
+ &link_down_cnt, &nim_interr, &lh_local_fault,
+ &lh_remote_fault, &lh_internal_local_fault,
+ &lh_received_local_fault);
+
+ assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
+ state->nim_present = nthw_gpio_phy_is_module_present(gpio_phy, (uint8_t)port);
+ state->lh_nim_absent = !state->nim_present;
+ state->link_up = phy_link_state ? true : false;
+
+ {
+ static char lsbuf[NUM_ADAPTER_MAX][NUM_ADAPTER_PORTS_MAX][256];
+ char buf[255];
+ const int adapter_no = drv->adapter_no;
+ snprintf(buf, sizeof(buf),
+ "%s: Port = %d: abs = %u, phy_link_state = %u, lh_abs = %u, "
+ "ll_phy_link_state = %u, "
+ "link_down_cnt = %u, nim_interr = %u, lh_local_fault = %u, lh_remote_fault = "
+ "%u, lh_internal_local_fault = %u, lh_received_local_fault = %u",
+ drv->mp_adapter_id_str, mac_pcs->mn_instance, abs, phy_link_state, lh_abs,
+ ll_phy_link_state, link_down_cnt, nim_interr, lh_local_fault,
+ lh_remote_fault, lh_internal_local_fault, lh_received_local_fault);
+
+ if (strcmp(lsbuf[adapter_no][port], buf) != 0) {
+ snprintf(lsbuf[adapter_no][port], sizeof(lsbuf[adapter_no][port]), "%s",
+ buf);
+ lsbuf[adapter_no][port][sizeof(lsbuf[adapter_no][port]) - 1U] = '\0';
+ NT_LOG(DBG, NTNIC, "%s\n", lsbuf[adapter_no][port]);
+ }
+ }
+ return 0;
+}
+
/*
* Check whether a NIM module is present
*/
@@ -20,6 +182,69 @@ static bool _nim_is_present(nthw_gpio_phy_t *gpio_phy, uint8_t if_no)
return nthw_gpio_phy_is_module_present(gpio_phy, if_no);
}
+/*
+ * Enable RX
+ */
+static int _enable_rx(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ (void)drv; /* unused */
+ nthw_mac_pcs_set_rx_enable(mac_pcs, true);
+ return 0;
+}
+
+/*
+ * Enable TX
+ */
+static int _enable_tx(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ (void)drv; /* unused */
+ nthw_mac_pcs_set_tx_enable(mac_pcs, true);
+ nthw_mac_pcs_set_tx_sel_host(mac_pcs, true);
+ return 0;
+}
+
+/*
+ * Disable RX
+ */
+static int _disable_rx(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ (void)drv; /* unused */
+ nthw_mac_pcs_set_rx_enable(mac_pcs, false);
+ return 0;
+}
+
+/*
+ * Disable TX
+ */
+static int _disable_tx(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ (void)drv; /* unused */
+ nthw_mac_pcs_set_tx_enable(mac_pcs, false);
+ nthw_mac_pcs_set_tx_sel_host(mac_pcs, false);
+ return 0;
+}
+
+/*
+ * Check link once NIM is installed and link can be expected.
+ */
+static int check_link_state(adapter_info_t *drv, nthw_mac_pcs_t *mac_pcs)
+{
+ bool rst_required;
+ bool ber;
+ bool fec_all_locked;
+
+ rst_required = nthw_mac_pcs_reset_required(mac_pcs);
+
+ ber = nthw_mac_pcs_get_hi_ber(mac_pcs);
+
+ fec_all_locked = nthw_mac_pcs_get_fec_stat_all_am_locked(mac_pcs);
+
+ if (rst_required || ber || !fec_all_locked)
+ _reset_rx(drv, mac_pcs);
+
+ return 0;
+}
+
/*
* Initialize NIM, Code based on nt200e3_2_ptp.cpp: MyPort::createNim()
*/
@@ -31,6 +256,7 @@ static int _create_nim(adapter_info_t *drv, int port, bool enable)
nim_i2c_ctx_t *nim_ctx;
sfp_nim_state_t nim;
nt4ga_link_t *link_info = &drv->nt4ga_link;
+ nthw_mac_pcs_t *mac_pcs = &link_info->u.var100g.mac_pcs100g[port];
assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
assert(link_info->variables_initialized);
@@ -46,6 +272,12 @@ static int _create_nim(adapter_info_t *drv, int port, bool enable)
return 0;
}
+ if (!enable) {
+ _disable_rx(drv, mac_pcs);
+ _disable_tx(drv, mac_pcs);
+ _reset_rx(drv, mac_pcs);
+ }
+
/*
* Perform PHY reset.
*/
@@ -114,14 +346,29 @@ static int _create_nim(adapter_info_t *drv, int port, bool enable)
* The function shall not assume anything about the state of the adapter
* and/or port.
*/
-static int _port_init(adapter_info_t *drv, int port)
+static int _port_init(adapter_info_t *drv, nthw_fpga_t *fpga, int port)
{
+ int adapter_id;
+ int hw_id;
int res;
nt4ga_link_t *link_info = &drv->nt4ga_link;
+ nthw_mac_pcs_t *mac_pcs;
+
assert(port >= 0 && port < NUM_ADAPTER_PORTS_MAX);
assert(link_info->variables_initialized);
+ if (fpga && fpga->p_fpga_info) {
+ adapter_id = fpga->p_fpga_info->n_nthw_adapter_id;
+ hw_id = fpga->p_fpga_info->nthw_hw_info.hw_id;
+
+ } else {
+ adapter_id = -1;
+ hw_id = -1;
+ }
+
+ mac_pcs = &link_info->u.var100g.mac_pcs100g[port];
+
/*
* Phase 1. Pre-state machine (`port init` functions)
* 1.1) nt4ga_adapter::port_init()
@@ -134,6 +381,28 @@ static int _port_init(adapter_info_t *drv, int port)
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_mac_pcs_set_led_mode(mac_pcs, NTHW_MAC_PCS_LED_AUTO);
+ nthw_mac_pcs_set_receiver_equalization_mode(mac_pcs, nthw_mac_pcs_receiver_mode_lpm);
+
+ /*
+ * NT200A01 build 2 HW and NT200A02 that require GTY polarity swap
+ * if (adapter is `NT200A01 build 2 HW or NT200A02`)
+ */
+ if (adapter_id == NT_HW_ADAPTER_ID_NT200A02 || hw_id == 2)
+ (void)_swap_tx_rx_polarity(drv, mac_pcs, port, true);
+
+ nthw_mac_pcs_set_ts_eop(mac_pcs, true); /* end-of-frame timestamping */
+
+ /* Work in ABSOLUTE timing mode, don't set IFG mode. */
+
+ /* Phase 2. Pre-state machine (`setup` functions) */
+
+ /* 2.1) nt200a0x.cpp:Myport::setup() */
+ NT_LOG(DBG, NTNIC, "%s: Setting up port %d\n", drv->mp_port_id_str[port], port);
+
+ NT_LOG(DBG, NTNIC, "%s: Port %d: PHY TX enable\n", drv->mp_port_id_str[port], port);
+ _enable_tx(drv, mac_pcs);
+ _reset_rx(drv, mac_pcs);
/* Phase 3. Link state machine steps */
@@ -147,6 +416,50 @@ static int _port_init(adapter_info_t *drv, int port)
NT_LOG(DBG, NTNIC, "%s: NIM initialized\n", drv->mp_port_id_str[port]);
+ /* 3.2) MyPort::nimReady() */
+
+ /* 3.3) MyPort::nimReady100Gb() */
+
+ /* Setting FEC resets the lane counter in one half of the GMF */
+ nthw_mac_pcs_set_fec(mac_pcs, true);
+ NT_LOG(DBG, NTNIC, "%s: Port %d: HOST FEC enabled\n", drv->mp_port_id_str[port], port);
+
+ if (adapter_id == NT_HW_ADAPTER_ID_NT200A02 || hw_id == 2) {
+ const uint8_t pre = 5;
+ const uint8_t diff = 25;
+ const uint8_t post = 12;
+
+ uint8_t lane = 0;
+
+ for (lane = 0; lane < 4; lane++)
+ nthw_mac_pcs_set_gty_tx_tuning(mac_pcs, lane, pre, diff, post);
+
+ } else {
+ NT_LOG(ERR, NTNIC, "Unhandled AdapterId/HwId: %02x_hwid%d\n", adapter_id, hw_id);
+ assert(0);
+ }
+
+ _reset_rx(drv, mac_pcs);
+
+ /*
+ * 3.4) MyPort::setLinkState()
+ *
+ * Compensation = 1640 - dly
+ * CMAC-core dly 188 ns
+ * FEC no correction 87 ns
+ * FEC active correction 211
+ */
+ if (nthw_mac_pcs_get_fec_valid(mac_pcs))
+ nthw_mac_pcs_set_timestamp_comp_rx(mac_pcs, (1640 - 188 - 211));
+
+ else
+ nthw_mac_pcs_set_timestamp_comp_rx(mac_pcs, (1640 - 188 - 87));
+
+ /* 3.5) uint32_t MyPort::macConfig(nt_link_state_t link_state) */
+ _enable_rx(drv, mac_pcs);
+
+ nthw_mac_pcs_set_host_loopback(mac_pcs, false);
+
return res;
}
@@ -163,7 +476,9 @@ static int _common_ptp_nim_state_machine(void *data)
const int nb_ports = fpga_info->n_phy_ports;
uint32_t last_lpbk_mode[NUM_ADAPTER_PORTS_MAX];
+ nim_i2c_ctx_t *nim_ctx;
link_state_t *link_state;
+ nthw_mac_pcs_t *mac_pcs;
nthw_gpio_phy_t *gpio_phy;
if (!fpga) {
@@ -172,7 +487,9 @@ static int _common_ptp_nim_state_machine(void *data)
}
assert(adapter_no >= 0 && adapter_no < NUM_ADAPTER_MAX);
+ nim_ctx = link_info->u.var100g.nim_ctx;
link_state = link_info->link_state;
+ mac_pcs = link_info->u.var100g.mac_pcs100g;
gpio_phy = link_info->u.var100g.gpio_phy;
monitor_task_is_running[adapter_no] = 1;
@@ -183,8 +500,10 @@ static int _common_ptp_nim_state_machine(void *data)
while (monitor_task_is_running[adapter_no]) {
int i;
+ static bool reported_link[NUM_ADAPTER_PORTS_MAX] = { false };
for (i = 0; i < nb_ports; i++) {
+ link_state_t new_link_state;
const bool is_port_disabled = link_info->port_action[i].port_disable;
const bool was_port_disabled = link_state[i].link_disabled;
const bool disable_port = is_port_disabled && !was_port_disabled;
@@ -200,6 +519,7 @@ static int _common_ptp_nim_state_machine(void *data)
memset(&link_state[i], 0, sizeof(link_state[i]));
link_info->link_info[i].link_speed = NT_LINK_SPEED_UNKNOWN;
link_state[i].link_disabled = true;
+ reported_link[i] = false;
/* Turn off laser and LED, etc. */
(void)_create_nim(drv, i, false);
NT_LOG(DBG, NTNIC, "%s: Port %i is disabled\n",
@@ -223,12 +543,17 @@ static int _common_ptp_nim_state_machine(void *data)
* If there is no Nim present, we need to initialize the
* port anyway
*/
- _port_init(drv, i);
+ _port_init(drv, fpga, i);
}
NT_LOG(INF, NTNIC, "%s: Loopback mode changed=%u\n",
drv->mp_port_id_str[i],
link_info->port_action[i].port_lpbk_mode);
+ _set_loopback(drv,
+ &mac_pcs[i],
+ i,
+ link_info->port_action[i].port_lpbk_mode,
+ last_lpbk_mode[i]);
if (link_info->port_action[i].port_lpbk_mode == 1)
link_state[i].link_up = true;
@@ -237,6 +562,65 @@ static int _common_ptp_nim_state_machine(void *data)
continue;
}
+ (void)_link_state_build(drv, &mac_pcs[i], &gpio_phy[i], i, &new_link_state,
+ is_port_disabled);
+
+ if (!new_link_state.nim_present) {
+ if (link_state[i].nim_present) {
+ NT_LOG(INF, NTNIC, "%s: NIM module removed\n",
+ drv->mp_port_id_str[i]);
+ }
+
+ link_state[i] = new_link_state;
+ continue;
+ }
+
+ /* NIM module is present */
+ if (new_link_state.lh_nim_absent || !link_state[i].nim_present) {
+ sfp_nim_state_t new_state;
+
+ NT_LOG(DBG, NTNIC, "%s: NIM module inserted\n",
+ drv->mp_port_id_str[i]);
+
+ if (_port_init(drv, fpga, i)) {
+ NT_LOG(ERR, NTNIC,
+ "%s: Failed to initialize NIM module\n",
+ drv->mp_port_id_str[i]);
+ continue;
+ }
+
+ if (nim_state_build(&nim_ctx[i], &new_state)) {
+ NT_LOG(ERR, NTNIC, "%s: Cannot read basic NIM data\n",
+ drv->mp_port_id_str[i]);
+ continue;
+ }
+
+ assert(new_state.br); /* Cannot be zero if NIM is present */
+ NT_LOG(DBG, NTNIC,
+ "%s: NIM id = %u (%s), br = %u, vendor = '%s', pn = '%s', sn='%s'\n",
+ drv->mp_port_id_str[i], nim_ctx->nim_id,
+ nim_id_to_text(nim_ctx->nim_id), (unsigned int)new_state.br,
+ nim_ctx->vendor_name, nim_ctx->prod_no, nim_ctx->serial_no);
+
+ (void)_link_state_build(drv, &mac_pcs[i], &gpio_phy[i], i,
+ &link_state[i], is_port_disabled);
+
+ NT_LOG(DBG, NTNIC, "%s: NIM module initialized\n",
+ drv->mp_port_id_str[i]);
+ continue;
+ }
+
+ if (reported_link[i] != new_link_state.link_up) {
+ NT_LOG(INF, NTNIC, "%s: link is %s\n", drv->mp_port_id_str[i],
+ (new_link_state.link_up ? "up" : "down"));
+ link_info->link_info[i].link_speed =
+ (new_link_state.link_up ? NT_LINK_SPEED_100G
+ : NT_LINK_SPEED_UNKNOWN);
+ link_state[i].link_up = new_link_state.link_up;
+ reported_link[i] = new_link_state.link_up;
+ }
+
+ check_link_state(drv, &mac_pcs[i]);
} /* end-for */
if (monitor_task_is_running[adapter_no])
@@ -280,6 +664,7 @@ static int nt4ga_link_100g_ports_init(struct adapter_info_s *p_adapter_info, nth
assert(adapter_no >= 0 && adapter_no < NUM_ADAPTER_MAX);
if (res == 0 && !p_adapter_info->nt4ga_link.variables_initialized) {
+ nthw_mac_pcs_t *mac_pcs = p_adapter_info->nt4ga_link.u.var100g.mac_pcs100g;
nim_i2c_ctx_t *nim_ctx = p_adapter_info->nt4ga_link.u.var100g.nim_ctx;
nthw_gpio_phy_t *gpio_phy = p_adapter_info->nt4ga_link.u.var100g.gpio_phy;
int i;
@@ -287,6 +672,10 @@ static int nt4ga_link_100g_ports_init(struct adapter_info_s *p_adapter_info, nth
for (i = 0; i < nb_ports; i++) {
/* 2 + adapter port number */
const uint8_t instance = (uint8_t)(2U + i);
+ res = nthw_mac_pcs_init(&mac_pcs[i], fpga, i /* int n_instance */);
+
+ if (res != 0)
+ break;
res = nthw_iic_init(&nim_ctx[i].hwiic, fpga, instance, 8);
@@ -38,6 +38,7 @@ sources = files(
'nthw/core/nthw_hif.c',
'nthw/core/nthw_i2cm.c',
'nthw/core/nthw_iic.c',
+ 'nthw/core/nthw_mac_pcs.c',
'nthw/core/nthw_pcie3.c',
'nthw/core/nthw_sdc.c',
'nthw/core/nthw_si5340.c',
@@ -18,6 +18,7 @@
#include "nthw_i2cm.h"
#include "nthw_gpio_phy.h"
+#include "nthw_mac_pcs.h"
#include "nthw_sdc.h"
#include "nthw_si5340.h"
new file mode 100644
@@ -0,0 +1,250 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef NTHW_MAC_PCS_H_
+#define NTHW_MAC_PCS_H_
+
+enum nthw_mac_pcs_led_mode_e {
+ NTHW_MAC_PCS_LED_AUTO = 0x00,
+ NTHW_MAC_PCS_LED_ON = 0x01,
+ NTHW_MAC_PCS_LED_OFF = 0x02,
+ NTHW_MAC_PCS_LED_PORTID = 0x03,
+};
+
+#define nthw_mac_pcs_receiver_mode_dfe (0)
+#define nthw_mac_pcs_receiver_mode_lpm (1)
+
+struct nthw_mac_pcs {
+ uint8_t m_port_no;
+
+ nthw_fpga_t *mp_fpga;
+ nthw_module_t *mp_mod_mac_pcs;
+ int mn_instance;
+
+ /* Block lock status */
+ nthw_field_t *mp_fld_block_lock_lock;
+ uint32_t m_fld_block_lock_lock_mask;
+
+ /* Lane lock status */
+ nthw_field_t *mp_fld_vl_demuxed_lock;
+ uint32_t m_fld_vl_demuxed_lock_mask;
+
+ /* GTY_STAT */
+ nthw_field_t *mp_fld_gty_stat_rx_rst_done0;
+ nthw_field_t *mp_fld_gty_stat_rx_rst_done1;
+ nthw_field_t *mp_fld_gty_stat_rx_rst_done2;
+ nthw_field_t *mp_fld_gty_stat_rx_rst_done3;
+ nthw_field_t *mp_fld_gty_stat_tx_rst_done0;
+ nthw_field_t *mp_fld_gty_stat_tx_rst_done1;
+ nthw_field_t *mp_fld_gty_stat_tx_rst_done2;
+ nthw_field_t *mp_fld_gty_stat_tx_rst_done3;
+ uint32_t m_fld_gty_stat_rx_rst_done_mask;
+ uint32_t m_fld_gty_stat_tx_rst_done_mask;
+
+ /* GTY_LOOP */
+ nthw_register_t *mp_reg_gty_loop;
+ nthw_field_t *mp_fld_gty_loop_gt_loop0;
+ nthw_field_t *mp_fld_gty_loop_gt_loop1;
+ nthw_field_t *mp_fld_gty_loop_gt_loop2;
+ nthw_field_t *mp_fld_gty_loop_gt_loop3;
+
+ /* MAC_PCS_CONFIG */
+ nthw_field_t *mp_fld_pcs_config_tx_path_rst;
+ nthw_field_t *mp_fld_pcs_config_rx_path_rst;
+ nthw_field_t *mp_fld_pcs_config_rx_enable;
+ nthw_field_t *mp_fld_pcs_config_rx_force_resync;
+ nthw_field_t *mp_fld_pcs_config_rx_test_pattern;
+ nthw_field_t *mp_fld_pcs_config_tx_enable;
+ nthw_field_t *mp_fld_pcs_config_tx_send_idle;
+ nthw_field_t *mp_fld_pcs_config_tx_send_rfi;
+ nthw_field_t *mp_fld_pcs_config_tx_test_pattern;
+
+ /* STAT PCS */
+ nthw_field_t *mp_fld_stat_pcs_rx_status;
+ nthw_field_t *mp_fld_stat_pcs_rx_aligned;
+ nthw_field_t *mp_fld_stat_pcs_rx_aligned_err;
+ nthw_field_t *mp_fld_stat_pcs_rx_misaligned;
+ nthw_field_t *mp_fld_stat_pcs_rx_internal_local_fault;
+ nthw_field_t *mp_fld_stat_pcs_rx_received_local_fault;
+ nthw_field_t *mp_fld_stat_pcs_rx_local_fault;
+ nthw_field_t *mp_fld_stat_pcs_rx_remote_fault;
+ nthw_field_t *mp_fld_stat_pcs_rx_hi_ber;
+
+ /* STAT_PCS_RX_LATCH */
+ nthw_field_t *mp_fld_stat_pcs_rx_latch_status;
+
+ /* PHYMAC_MISC */
+ nthw_field_t *mp_fld_phymac_misc_tx_sel_host;
+ nthw_field_t *mp_fld_phymac_misc_tx_sel_tfg;
+ nthw_field_t *mp_fld_phymac_misc_tx_sel_rx_loop;
+ nthw_field_t *mp_fld_phymac_misc_ts_eop;
+
+ /* LINK_SUMMARY */
+ nthw_register_t *mp_reg_link_summary;
+ nthw_field_t *mp_fld_link_summary_abs;
+ nthw_field_t *mp_fld_link_summary_nt_phy_link_state;
+ nthw_field_t *mp_fld_link_summary_lh_abs;
+ nthw_field_t *mp_fld_link_summary_ll_nt_phy_link_state;
+ nthw_field_t *mp_fld_link_summary_link_down_cnt;
+ nthw_field_t *mp_fld_link_summary_nim_interr;
+ nthw_field_t *mp_fld_link_summary_lh_local_fault;
+ nthw_field_t *mp_fld_link_summary_lh_remote_fault;
+ nthw_field_t *mp_fld_link_summary_local_fault;
+ nthw_field_t *mp_fld_link_summary_remote_fault;
+
+ /* BIP_ERR */
+ nthw_register_t *mp_reg_bip_err;
+ nthw_field_t *mp_fld_reg_bip_err_bip_err;
+
+ /* FEC_CTRL */
+ nthw_register_t *mp_reg_fec_ctrl;
+ nthw_field_t *mp_field_fec_ctrl_reg_rs_fec_ctrl_in;
+
+ /* FEC_STAT */
+ nthw_register_t *mp_reg_fec_stat;
+ nthw_field_t *mp_field_fec_stat_bypass;
+ nthw_field_t *mp_field_fec_stat_valid;
+ nthw_field_t *mp_field_fec_stat_am_lock0;
+ nthw_field_t *mp_field_fec_stat_am_lock1;
+ nthw_field_t *mp_field_fec_stat_am_lock2;
+ nthw_field_t *mp_field_fec_stat_am_lock3;
+ nthw_field_t *mp_field_fec_stat_fec_lane_algn;
+
+ /* FEC Corrected code word count */
+ nthw_register_t *mp_reg_fec_cw_cnt;
+ nthw_field_t *mp_field_fec_cw_cnt_cw_cnt;
+
+ /* FEC Uncorrected code word count */
+ nthw_register_t *mp_reg_fec_ucw_cnt;
+ nthw_field_t *mp_field_fec_ucw_cnt_ucw_cnt;
+
+ /* GTY_RX_BUF_STAT */
+ nthw_register_t *mp_reg_gty_rx_buf_stat;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat0;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat1;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat2;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat3;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed0;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed1;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed2;
+ nthw_field_t *mp_field_gty_rx_buf_stat_rx_buf_stat_changed3;
+
+ /* GTY_PRE_CURSOR */
+ nthw_register_t *mp_reg_gty_pre_cursor;
+ nthw_field_t *mp_field_gty_pre_cursor_tx_pre_csr0;
+ nthw_field_t *mp_field_gty_pre_cursor_tx_pre_csr1;
+ nthw_field_t *mp_field_gty_pre_cursor_tx_pre_csr2;
+ nthw_field_t *mp_field_gty_pre_cursor_tx_pre_csr3;
+
+ /* GTY_DIFF_CTL */
+ nthw_register_t *mp_reg_gty_diff_ctl;
+ nthw_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl0;
+ nthw_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl1;
+ nthw_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl2;
+ nthw_field_t *mp_field_gty_gty_diff_ctl_tx_diff_ctl3;
+
+ /* GTY_POST_CURSOR */
+ nthw_register_t *mp_reg_gty_post_cursor;
+ nthw_field_t *mp_field_gty_post_cursor_tx_post_csr0;
+ nthw_field_t *mp_field_gty_post_cursor_tx_post_csr1;
+ nthw_field_t *mp_field_gty_post_cursor_tx_post_csr2;
+ nthw_field_t *mp_field_gty_post_cursor_tx_post_csr3;
+
+ /* GTY_CTL */
+ nthw_register_t *mp_reg_gty_ctl;
+ nthw_register_t *mp_reg_gty_ctl_tx;
+ nthw_field_t *mp_field_gty_ctl_tx_pol0;
+ nthw_field_t *mp_field_gty_ctl_tx_pol1;
+ nthw_field_t *mp_field_gty_ctl_tx_pol2;
+ nthw_field_t *mp_field_gty_ctl_tx_pol3;
+ nthw_field_t *mp_field_gty_ctl_rx_pol0;
+ nthw_field_t *mp_field_gty_ctl_rx_pol1;
+ nthw_field_t *mp_field_gty_ctl_rx_pol2;
+ nthw_field_t *mp_field_gty_ctl_rx_pol3;
+ nthw_field_t *mp_field_gty_ctl_rx_lpm_en0;
+ nthw_field_t *mp_field_gty_ctl_rx_lpm_en1;
+ nthw_field_t *mp_field_gty_ctl_rx_lpm_en2;
+ nthw_field_t *mp_field_gty_ctl_rx_lpm_en3;
+ nthw_field_t *mp_field_gty_ctl_rx_equa_rst0;
+ nthw_field_t *mp_field_gty_ctl_rx_equa_rst1;
+ nthw_field_t *mp_field_gty_ctl_rx_equa_rst2;
+ nthw_field_t *mp_field_gty_ctl_rx_equa_rst3;
+
+ /* DEBOUNCE_CTRL */
+ nthw_register_t *mp_reg_debounce_ctrl;
+ nthw_field_t *mp_field_debounce_ctrl_nt_port_ctrl;
+
+ /* TIMESTAMP_COMP */
+ nthw_register_t *mp_reg_time_stamp_comp;
+ nthw_field_t *mp_field_time_stamp_comp_rx_dly;
+ nthw_field_t *mp_field_time_stamp_comp_tx_dly;
+
+ /* STAT_PCS_RX */
+ nthw_register_t *mp_reg_stat_pcs_rx;
+
+ /* STAT_PCS_RX */
+ nthw_register_t *mp_reg_stat_pcs_rx_latch;
+
+ /* PHYMAC_MISC */
+ nthw_register_t *mp_reg_phymac_misc;
+
+ /* BLOCK_LOCK */
+ nthw_register_t *mp_reg_block_lock;
+};
+
+typedef struct nthw_mac_pcs nthw_mac_pcs_t;
+
+int nthw_mac_pcs_init(nthw_mac_pcs_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+void nthw_mac_pcs_tx_path_rst(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_rx_path_rst(nthw_mac_pcs_t *p, bool enable);
+bool nthw_mac_pcs_is_rx_path_rst(nthw_mac_pcs_t *p);
+/* wrapper - for ease of use */
+void nthw_mac_pcs_set_rx_enable(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_tx_enable(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_tx_sel_host(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_tx_sel_tfg(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_ts_eop(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_host_loopback(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_set_line_loopback(nthw_mac_pcs_t *p, bool enable);
+void nthw_mac_pcs_reset_bip_counters(nthw_mac_pcs_t *p);
+bool nthw_mac_pcs_get_hi_ber(nthw_mac_pcs_t *p);
+
+void nthw_mac_pcs_get_link_summary(nthw_mac_pcs_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_local_fault,
+ uint32_t *p_remote_fault);
+
+bool nthw_mac_pcs_reset_required(nthw_mac_pcs_t *p);
+void nthw_mac_pcs_set_fec(nthw_mac_pcs_t *p, bool enable);
+bool nthw_mac_pcs_get_fec_bypass(nthw_mac_pcs_t *p);
+bool nthw_mac_pcs_get_fec_valid(nthw_mac_pcs_t *p);
+bool nthw_mac_pcs_get_fec_stat_all_am_locked(nthw_mac_pcs_t *p);
+void nthw_mac_pcs_reset_fec_counters(nthw_mac_pcs_t *p);
+void nthw_mac_pcs_set_gty_tx_tuning(nthw_mac_pcs_t *p,
+ uint8_t lane,
+ uint8_t tx_pre_csr,
+ uint8_t tx_diff_ctl,
+ uint8_t tx_post_csr);
+void nthw_mac_pcs_swap_gty_tx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap);
+void nthw_mac_pcs_swap_gty_rx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap);
+void nthw_mac_pcs_set_receiver_equalization_mode(nthw_mac_pcs_t *p, uint8_t mode);
+void nthw_mac_pcs_set_led_mode(nthw_mac_pcs_t *p, uint8_t mode);
+void nthw_mac_pcs_set_timestamp_comp_rx(nthw_mac_pcs_t *p, uint16_t rx_dly);
+void nthw_mac_pcs_set_port_no(nthw_mac_pcs_t *p, uint8_t port_no);
+
+uint32_t nthw_mac_pcs_get_fld_block_lock_lock(nthw_mac_pcs_t *p);
+uint32_t nthw_mac_pcs_get_fld_block_lock_lock_mask(nthw_mac_pcs_t *p);
+uint32_t nthw_mac_pcs_get_fld_lane_lock_lock(nthw_mac_pcs_t *p);
+uint32_t nthw_mac_pcs_get_fld_lane_lock_lock_mask(nthw_mac_pcs_t *p);
+
+#endif /* NTHW_MAC_PCS_H_ */
new file mode 100644
@@ -0,0 +1,864 @@
+/*
+ * 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_mac_pcs.h"
+
+#define NTHW_MAC_PCS_LANES (20)
+
+static const uint8_t c_pcs_lanes = NTHW_MAC_PCS_LANES;
+static const uint8_t c_mac_pcs_receiver_mode_dfe;
+
+/*
+ * Parameters:
+ * p != NULL: init struct pointed to by p
+ * p == NULL: check fpga module(s) presence (but no struct to init)
+ *
+ * Return value:
+ * <0: if p == NULL then fpga module(s) is/are not present.
+ * if p != NULL then fpga module(s) is/are not present, struct undefined
+ * ==0: if p == NULL then fpga module(s) is/are present (no struct to init)
+ * : if p != NULL then fpga module(s) is/are present and struct initialized
+ */
+int nthw_mac_pcs_init(nthw_mac_pcs_t *p, nthw_fpga_t *p_fpga, int n_instance)
+{
+ nthw_module_t *mod = nthw_fpga_query_module(p_fpga, MOD_MAC_PCS, n_instance);
+
+ if (p == NULL)
+ return mod == NULL ? -1 : 0;
+
+ if (mod == NULL) {
+ NT_LOG(ERR, NTHW, "%s: MAC_PCS %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_mac_pcs = mod;
+
+ assert(n_instance >= 0 && n_instance <= 255);
+ nthw_mac_pcs_set_port_no(p, (uint8_t)n_instance);
+
+ {
+ nthw_register_t *p_reg_block_lock, *p_reg_stat_pcs_rx, *p_reg_stat_pcs_rx_latch;
+ nthw_register_t *p_reg_vl_demuxed, *p_reg_gty_stat, *p_reg_pcs_config,
+ *p_reg_phymac_misc;
+ const int product_id = nthw_fpga_get_product_id(p_fpga);
+
+ p_reg_block_lock = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_BLOCK_LOCK);
+ p->mp_reg_block_lock = p_reg_block_lock;
+ p->mp_fld_block_lock_lock =
+ nthw_register_get_field(p_reg_block_lock, MAC_PCS_BLOCK_LOCK_LOCK);
+
+ p_reg_stat_pcs_rx =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_STAT_PCS_RX);
+ p->mp_reg_stat_pcs_rx = p_reg_stat_pcs_rx;
+ p->mp_fld_stat_pcs_rx_status =
+ nthw_register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_STATUS);
+ p->mp_fld_stat_pcs_rx_aligned =
+ nthw_register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_ALIGNED);
+ p->mp_fld_stat_pcs_rx_aligned_err =
+ nthw_register_get_field(p_reg_stat_pcs_rx,
+ MAC_PCS_STAT_PCS_RX_ALIGNED_ERR);
+ p->mp_fld_stat_pcs_rx_misaligned =
+ nthw_register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_MISALIGNED);
+ p->mp_fld_stat_pcs_rx_internal_local_fault =
+ nthw_register_get_field(p_reg_stat_pcs_rx,
+ MAC_PCS_STAT_PCS_RX_INTERNAL_LOCAL_FAULT);
+ p->mp_fld_stat_pcs_rx_received_local_fault =
+ nthw_register_get_field(p_reg_stat_pcs_rx,
+ MAC_PCS_STAT_PCS_RX_RECEIVED_LOCAL_FAULT);
+ p->mp_fld_stat_pcs_rx_local_fault =
+ nthw_register_get_field(p_reg_stat_pcs_rx,
+ MAC_PCS_STAT_PCS_RX_LOCAL_FAULT);
+ p->mp_fld_stat_pcs_rx_remote_fault =
+ nthw_register_get_field(p_reg_stat_pcs_rx,
+ MAC_PCS_STAT_PCS_RX_REMOTE_FAULT);
+ p->mp_fld_stat_pcs_rx_hi_ber =
+ nthw_register_get_field(p_reg_stat_pcs_rx, MAC_PCS_STAT_PCS_RX_HI_BER);
+
+ p_reg_stat_pcs_rx_latch =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_STAT_PCS_RX_LATCH);
+ p->mp_reg_stat_pcs_rx_latch = p_reg_stat_pcs_rx_latch;
+ p->mp_fld_stat_pcs_rx_latch_status =
+ nthw_register_get_field(p_reg_stat_pcs_rx_latch,
+ MAC_PCS_STAT_PCS_RX_LATCH_STATUS);
+
+ p_reg_vl_demuxed = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_VL_DEMUXED);
+ p->mp_fld_vl_demuxed_lock =
+ nthw_register_get_field(p_reg_vl_demuxed, MAC_PCS_VL_DEMUXED_LOCK);
+
+ p_reg_gty_stat = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_STAT);
+ p->mp_fld_gty_stat_tx_rst_done0 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_0);
+ p->mp_fld_gty_stat_tx_rst_done1 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_1);
+ p->mp_fld_gty_stat_tx_rst_done2 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_2);
+ p->mp_fld_gty_stat_tx_rst_done3 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_TX_RST_DONE_3);
+ p->mp_fld_gty_stat_rx_rst_done0 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_0);
+ p->mp_fld_gty_stat_rx_rst_done1 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_1);
+ p->mp_fld_gty_stat_rx_rst_done2 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_2);
+ p->mp_fld_gty_stat_rx_rst_done3 =
+ nthw_register_get_field(p_reg_gty_stat, MAC_PCS_GTY_STAT_RX_RST_DONE_3);
+
+ p->m_fld_block_lock_lock_mask = 0;
+ p->m_fld_vl_demuxed_lock_mask = 0;
+ p->m_fld_gty_stat_tx_rst_done_mask = 0;
+ p->m_fld_gty_stat_rx_rst_done_mask = 0;
+
+ if (product_id == 9563) {
+ /* NT200A01_2X100 implements 20 virtual lanes */
+ p->m_fld_block_lock_lock_mask = (1 << 20) - 1;
+ /* NT200A01_2X100 implements 20 virtual lanes */
+ p->m_fld_vl_demuxed_lock_mask = (1 << 20) - 1;
+ p->m_fld_gty_stat_tx_rst_done_mask =
+ 1; /* NT200A01_2X100 implements 4 GTY */
+ p->m_fld_gty_stat_rx_rst_done_mask =
+ 1; /* NT200A01_2X100 implements 4 GTY */
+
+ } else {
+ /* Remember to add new product_ids */
+ assert(0);
+ }
+
+ p_reg_pcs_config =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_MAC_PCS_CONFIG);
+ p->mp_fld_pcs_config_tx_path_rst =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_TX_PATH_RST);
+ p->mp_fld_pcs_config_rx_path_rst =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_RX_PATH_RST);
+ p->mp_fld_pcs_config_rx_enable =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_RX_ENABLE);
+ p->mp_fld_pcs_config_rx_force_resync =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_RX_FORCE_RESYNC);
+ p->mp_fld_pcs_config_rx_test_pattern =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_RX_TEST_PATTERN);
+ p->mp_fld_pcs_config_tx_enable =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_TX_ENABLE);
+ p->mp_fld_pcs_config_tx_send_idle =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_TX_SEND_IDLE);
+ p->mp_fld_pcs_config_tx_send_rfi =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_TX_SEND_RFI);
+ p->mp_fld_pcs_config_tx_test_pattern =
+ nthw_register_get_field(p_reg_pcs_config,
+ MAC_PCS_MAC_PCS_CONFIG_TX_TEST_PATTERN);
+
+ p->mp_reg_gty_loop = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_LOOP);
+ p->mp_fld_gty_loop_gt_loop0 =
+ nthw_register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_0);
+ p->mp_fld_gty_loop_gt_loop1 =
+ nthw_register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_1);
+ p->mp_fld_gty_loop_gt_loop2 =
+ nthw_register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_2);
+ p->mp_fld_gty_loop_gt_loop3 =
+ nthw_register_get_field(p->mp_reg_gty_loop, MAC_PCS_GTY_LOOP_GT_LOOP_3);
+
+ p_reg_phymac_misc =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_PHYMAC_MISC);
+ p->mp_reg_phymac_misc = p_reg_phymac_misc;
+ p->mp_fld_phymac_misc_tx_sel_host =
+ nthw_register_get_field(p_reg_phymac_misc,
+ MAC_PCS_PHYMAC_MISC_TX_SEL_HOST);
+ p->mp_fld_phymac_misc_tx_sel_tfg =
+ nthw_register_get_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TX_SEL_TFG);
+ p->mp_fld_phymac_misc_tx_sel_rx_loop =
+ nthw_register_get_field(p_reg_phymac_misc,
+ MAC_PCS_PHYMAC_MISC_TX_SEL_RX_LOOP);
+
+ /* SOP or EOP TIMESTAMP */
+ p->mp_fld_phymac_misc_ts_eop =
+ nthw_register_query_field(p_reg_phymac_misc, MAC_PCS_PHYMAC_MISC_TS_EOP);
+
+ p->mp_reg_link_summary =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_LINK_SUMMARY);
+ p->mp_fld_link_summary_abs =
+ nthw_register_get_field(p->mp_reg_link_summary, MAC_PCS_LINK_SUMMARY_ABS);
+ p->mp_fld_link_summary_nt_phy_link_state =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_NT_PHY_LINK_STATE);
+ p->mp_fld_link_summary_lh_abs =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LH_ABS);
+ p->mp_fld_link_summary_ll_nt_phy_link_state =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LL_PHY_LINK_STATE);
+ p->mp_fld_link_summary_link_down_cnt =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LINK_DOWN_CNT);
+ p->mp_fld_link_summary_nim_interr =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_NIM_INTERR);
+ p->mp_fld_link_summary_lh_local_fault =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LH_LOCAL_FAULT);
+ p->mp_fld_link_summary_lh_remote_fault =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LH_REMOTE_FAULT);
+ p->mp_fld_link_summary_local_fault =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_LOCAL_FAULT);
+ p->mp_fld_link_summary_remote_fault =
+ nthw_register_get_field(p->mp_reg_link_summary,
+ MAC_PCS_LINK_SUMMARY_REMOTE_FAULT);
+
+ p->mp_reg_bip_err = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_BIP_ERR);
+ p->mp_fld_reg_bip_err_bip_err =
+ nthw_register_get_field(p->mp_reg_bip_err, MAC_PCS_BIP_ERR_BIP_ERR);
+
+ p->mp_reg_fec_ctrl = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_CTRL);
+ p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in =
+ nthw_register_get_field(p->mp_reg_fec_ctrl,
+ MAC_PCS_FEC_CTRL_RS_FEC_CTRL_IN);
+
+ p->mp_reg_fec_stat = nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_STAT);
+ p->mp_field_fec_stat_bypass =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_BYPASS);
+ p->mp_field_fec_stat_valid =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_VALID);
+ p->mp_field_fec_stat_am_lock0 =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_0);
+ p->mp_field_fec_stat_am_lock1 =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_1);
+ p->mp_field_fec_stat_am_lock2 =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_2);
+ p->mp_field_fec_stat_am_lock3 =
+ nthw_register_get_field(p->mp_reg_fec_stat, MAC_PCS_FEC_STAT_AM_LOCK_3);
+ p->mp_field_fec_stat_fec_lane_algn =
+ nthw_register_get_field(p->mp_reg_fec_stat,
+ MAC_PCS_FEC_STAT_FEC_LANE_ALGN);
+
+ p->mp_reg_fec_cw_cnt =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_CW_CNT);
+ p->mp_field_fec_cw_cnt_cw_cnt =
+ nthw_register_get_field(p->mp_reg_fec_cw_cnt, MAC_PCS_FEC_CW_CNT_CW_CNT);
+
+ p->mp_reg_fec_ucw_cnt =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_FEC_UCW_CNT);
+ p->mp_field_fec_ucw_cnt_ucw_cnt =
+ nthw_register_get_field(p->mp_reg_fec_ucw_cnt,
+ MAC_PCS_FEC_UCW_CNT_UCW_CNT);
+
+ /* GTY_PRE_CURSOR */
+ p->mp_reg_gty_pre_cursor =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_PRE_CURSOR);
+ p->mp_field_gty_pre_cursor_tx_pre_csr0 =
+ nthw_register_get_field(p->mp_reg_gty_pre_cursor,
+ MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_0);
+ p->mp_field_gty_pre_cursor_tx_pre_csr1 =
+ nthw_register_get_field(p->mp_reg_gty_pre_cursor,
+ MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_1);
+ p->mp_field_gty_pre_cursor_tx_pre_csr2 =
+ nthw_register_get_field(p->mp_reg_gty_pre_cursor,
+ MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_2);
+ p->mp_field_gty_pre_cursor_tx_pre_csr3 =
+ nthw_register_get_field(p->mp_reg_gty_pre_cursor,
+ MAC_PCS_GTY_PRE_CURSOR_TX_PRE_CSR_3);
+
+ /* GTY_DIFF_CTL */
+ p->mp_reg_gty_diff_ctl =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_DIFF_CTL);
+ p->mp_field_gty_gty_diff_ctl_tx_diff_ctl0 =
+ nthw_register_get_field(p->mp_reg_gty_diff_ctl,
+ MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_0);
+ p->mp_field_gty_gty_diff_ctl_tx_diff_ctl1 =
+ nthw_register_get_field(p->mp_reg_gty_diff_ctl,
+ MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_1);
+ p->mp_field_gty_gty_diff_ctl_tx_diff_ctl2 =
+ nthw_register_get_field(p->mp_reg_gty_diff_ctl,
+ MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_2);
+ p->mp_field_gty_gty_diff_ctl_tx_diff_ctl3 =
+ nthw_register_get_field(p->mp_reg_gty_diff_ctl,
+ MAC_PCS_GTY_DIFF_CTL_TX_DIFF_CTL_3);
+
+ /* GTY_POST_CURSOR */
+ p->mp_reg_gty_post_cursor =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_POST_CURSOR);
+ p->mp_field_gty_post_cursor_tx_post_csr0 =
+ nthw_register_get_field(p->mp_reg_gty_post_cursor,
+ MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_0);
+ p->mp_field_gty_post_cursor_tx_post_csr1 =
+ nthw_register_get_field(p->mp_reg_gty_post_cursor,
+ MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_1);
+ p->mp_field_gty_post_cursor_tx_post_csr2 =
+ nthw_register_get_field(p->mp_reg_gty_post_cursor,
+ MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_2);
+ p->mp_field_gty_post_cursor_tx_post_csr3 =
+ nthw_register_get_field(p->mp_reg_gty_post_cursor,
+ MAC_PCS_GTY_POST_CURSOR_TX_POST_CSR_3);
+
+ /* GTY_CTL */
+ p->mp_reg_gty_ctl = nthw_module_query_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_CTL);
+
+ if (p->mp_reg_gty_ctl) {
+ p->mp_field_gty_ctl_tx_pol0 =
+ nthw_register_get_field(p->mp_reg_gty_ctl,
+ MAC_PCS_GTY_CTL_TX_POLARITY_0);
+ p->mp_field_gty_ctl_tx_pol1 =
+ nthw_register_get_field(p->mp_reg_gty_ctl,
+ MAC_PCS_GTY_CTL_TX_POLARITY_1);
+ p->mp_field_gty_ctl_tx_pol2 =
+ nthw_register_get_field(p->mp_reg_gty_ctl,
+ MAC_PCS_GTY_CTL_TX_POLARITY_2);
+ p->mp_field_gty_ctl_tx_pol3 =
+ nthw_register_get_field(p->mp_reg_gty_ctl,
+ MAC_PCS_GTY_CTL_TX_POLARITY_3);
+
+ } else {
+ p->mp_reg_gty_ctl =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_CTL_RX);
+ p->mp_reg_gty_ctl_tx =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_GTY_CTL_TX);
+ p->mp_field_gty_ctl_tx_pol0 =
+ nthw_register_get_field(p->mp_reg_gty_ctl_tx,
+ MAC_PCS_GTY_CTL_TX_POLARITY_0);
+ p->mp_field_gty_ctl_tx_pol1 =
+ nthw_register_get_field(p->mp_reg_gty_ctl_tx,
+ MAC_PCS_GTY_CTL_TX_POLARITY_1);
+ p->mp_field_gty_ctl_tx_pol2 =
+ nthw_register_get_field(p->mp_reg_gty_ctl_tx,
+ MAC_PCS_GTY_CTL_TX_POLARITY_2);
+ p->mp_field_gty_ctl_tx_pol3 =
+ nthw_register_get_field(p->mp_reg_gty_ctl_tx,
+ MAC_PCS_GTY_CTL_TX_POLARITY_3);
+ }
+
+ p->mp_field_gty_ctl_rx_pol0 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_POLARITY_0);
+ p->mp_field_gty_ctl_rx_pol1 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_POLARITY_1);
+ p->mp_field_gty_ctl_rx_pol2 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_POLARITY_2);
+ p->mp_field_gty_ctl_rx_pol3 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_POLARITY_3);
+ p->mp_field_gty_ctl_rx_lpm_en0 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_LPM_EN_0);
+ p->mp_field_gty_ctl_rx_lpm_en1 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_LPM_EN_1);
+ p->mp_field_gty_ctl_rx_lpm_en2 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_LPM_EN_2);
+ p->mp_field_gty_ctl_rx_lpm_en3 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_LPM_EN_3);
+ p->mp_field_gty_ctl_rx_equa_rst0 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_EQUA_RST_0);
+ p->mp_field_gty_ctl_rx_equa_rst1 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_EQUA_RST_1);
+ p->mp_field_gty_ctl_rx_equa_rst2 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_EQUA_RST_2);
+ p->mp_field_gty_ctl_rx_equa_rst3 =
+ nthw_register_get_field(p->mp_reg_gty_ctl, MAC_PCS_GTY_CTL_RX_EQUA_RST_3);
+
+ /* DEBOUNCE_CTRL */
+ p->mp_reg_debounce_ctrl =
+ nthw_module_get_register(p->mp_mod_mac_pcs, MAC_PCS_DEBOUNCE_CTRL);
+ p->mp_field_debounce_ctrl_nt_port_ctrl =
+ nthw_register_get_field(p->mp_reg_debounce_ctrl,
+ MAC_PCS_DEBOUNCE_CTRL_NT_PORT_CTRL);
+
+ p->mp_reg_time_stamp_comp =
+ nthw_module_query_register(p->mp_mod_mac_pcs, MAC_PCS_TIMESTAMP_COMP);
+
+ if (p->mp_reg_time_stamp_comp) {
+ /* TIMESTAMP_COMP */
+ p->mp_field_time_stamp_comp_rx_dly =
+ nthw_register_get_field(p->mp_reg_time_stamp_comp,
+ MAC_PCS_TIMESTAMP_COMP_RX_DLY);
+ p->mp_field_time_stamp_comp_tx_dly =
+ nthw_register_get_field(p->mp_reg_time_stamp_comp,
+ MAC_PCS_TIMESTAMP_COMP_TX_DLY);
+ }
+ }
+ return 0;
+}
+
+void nthw_mac_pcs_set_rx_enable(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_pcs_config_rx_enable);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_pcs_config_rx_enable);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_pcs_config_rx_enable);
+}
+
+void nthw_mac_pcs_set_tx_enable(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_pcs_config_tx_enable);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_pcs_config_tx_enable);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_pcs_config_tx_enable);
+}
+
+void nthw_mac_pcs_set_tx_sel_host(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_phymac_misc_tx_sel_host);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_phymac_misc_tx_sel_host);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_phymac_misc_tx_sel_host);
+}
+
+void nthw_mac_pcs_set_tx_sel_tfg(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_phymac_misc_tx_sel_tfg);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_phymac_misc_tx_sel_tfg);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_phymac_misc_tx_sel_tfg);
+}
+
+void nthw_mac_pcs_set_ts_eop(nthw_mac_pcs_t *p, bool enable)
+{
+ if (p->mp_fld_phymac_misc_ts_eop) {
+ nthw_field_get_updated(p->mp_fld_phymac_misc_ts_eop);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_phymac_misc_ts_eop);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_phymac_misc_ts_eop);
+ }
+}
+
+void nthw_mac_pcs_tx_path_rst(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_pcs_config_tx_path_rst);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_pcs_config_tx_path_rst);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_pcs_config_tx_path_rst);
+}
+
+void nthw_mac_pcs_rx_path_rst(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_field_get_updated(p->mp_fld_pcs_config_rx_path_rst);
+
+ if (enable)
+ nthw_field_set_flush(p->mp_fld_pcs_config_rx_path_rst);
+
+ else
+ nthw_field_clr_flush(p->mp_fld_pcs_config_rx_path_rst);
+}
+
+bool nthw_mac_pcs_is_rx_path_rst(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_fld_pcs_config_rx_path_rst);
+}
+
+void nthw_mac_pcs_set_host_loopback(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_register_update(p->mp_reg_gty_loop);
+
+ if (enable) {
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop0, 2);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop1, 2);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop2, 2);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop3, 2);
+
+ } else {
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop0, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop1, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop2, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop3, 0);
+ }
+
+ nthw_register_flush(p->mp_reg_gty_loop, 1);
+}
+
+void nthw_mac_pcs_set_line_loopback(nthw_mac_pcs_t *p, bool enable)
+{
+ nthw_register_update(p->mp_reg_gty_loop);
+
+ if (enable) {
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop0, 4);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop1, 4);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop2, 4);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop3, 4);
+
+ } else {
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop0, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop1, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop2, 0);
+ nthw_field_set_val32(p->mp_fld_gty_loop_gt_loop3, 0);
+ }
+
+ nthw_register_flush(p->mp_reg_gty_loop, 1);
+}
+
+void nthw_mac_pcs_reset_bip_counters(nthw_mac_pcs_t *p)
+{
+ uint32_t lane_bit_errors[NTHW_MAC_PCS_LANES];
+ nthw_register_update(p->mp_reg_bip_err);
+ nthw_field_get_val(p->mp_fld_reg_bip_err_bip_err, (uint32_t *)lane_bit_errors,
+ ARRAY_SIZE(lane_bit_errors));
+
+ (void)c_pcs_lanes; /* unused - kill warning */
+}
+
+bool nthw_mac_pcs_get_hi_ber(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_fld_stat_pcs_rx_hi_ber);
+}
+
+void nthw_mac_pcs_get_link_summary(nthw_mac_pcs_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_local_fault,
+ uint32_t *p_remote_fault)
+{
+ nthw_register_update(p->mp_reg_link_summary);
+
+ if (p_abs)
+ *p_abs = nthw_field_get_val32(p->mp_fld_link_summary_abs);
+
+ if (p_nt_phy_link_state) {
+ *p_nt_phy_link_state =
+ nthw_field_get_val32(p->mp_fld_link_summary_nt_phy_link_state);
+ }
+
+ if (p_lh_abs)
+ *p_lh_abs = nthw_field_get_val32(p->mp_fld_link_summary_lh_abs);
+
+ if (p_ll_nt_phy_link_state) {
+ *p_ll_nt_phy_link_state =
+ nthw_field_get_val32(p->mp_fld_link_summary_ll_nt_phy_link_state);
+ }
+
+ if (p_link_down_cnt)
+ *p_link_down_cnt = nthw_field_get_val32(p->mp_fld_link_summary_link_down_cnt);
+
+ if (p_nim_interr)
+ *p_nim_interr = nthw_field_get_val32(p->mp_fld_link_summary_nim_interr);
+
+ if (p_lh_local_fault)
+ *p_lh_local_fault = nthw_field_get_val32(p->mp_fld_link_summary_lh_local_fault);
+
+ if (p_lh_remote_fault)
+ *p_lh_remote_fault = nthw_field_get_val32(p->mp_fld_link_summary_lh_remote_fault);
+
+ if (p_local_fault)
+ *p_local_fault = nthw_field_get_val32(p->mp_fld_link_summary_local_fault);
+
+ if (p_remote_fault)
+ *p_remote_fault = nthw_field_get_val32(p->mp_fld_link_summary_remote_fault);
+}
+
+/*
+ * Returns true if the lane/block lock bits indicate that a reset is required.
+ * This is the case if Block/Lane lock is not all zero but not all set either.
+ */
+bool nthw_mac_pcs_reset_required(nthw_mac_pcs_t *p)
+{
+ uint32_t block_lock = nthw_mac_pcs_get_fld_block_lock_lock(p);
+ uint32_t lane_lock = nthw_mac_pcs_get_fld_lane_lock_lock(p);
+ uint32_t block_lock_mask = nthw_mac_pcs_get_fld_block_lock_lock_mask(p);
+ uint32_t lane_lock_mask = nthw_mac_pcs_get_fld_lane_lock_lock_mask(p);
+
+ return ((block_lock != 0) && (block_lock != block_lock_mask)) ||
+ ((lane_lock != 0) && (lane_lock != lane_lock_mask));
+}
+
+void nthw_mac_pcs_set_fec(nthw_mac_pcs_t *p, bool enable)
+{
+ NT_LOG(DBG, NTHW, "Port %u: Set FEC: %u\n", p->m_port_no, enable);
+
+ nthw_field_get_updated(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in);
+
+ if (enable)
+ nthw_field_set_val_flush32(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in, 0);
+
+ else
+ nthw_field_set_val_flush32(p->mp_field_fec_ctrl_reg_rs_fec_ctrl_in, (1 << 5) - 1);
+
+ /* Both Rx and Tx must be reset for new FEC state to become active */
+ nthw_mac_pcs_rx_path_rst(p, true);
+ nthw_mac_pcs_tx_path_rst(p, true);
+ nt_os_wait_usec(10000); /* 10ms */
+
+ nthw_mac_pcs_rx_path_rst(p, false);
+ nthw_mac_pcs_tx_path_rst(p, false);
+ nt_os_wait_usec(10000); /* 10ms */
+}
+
+bool nthw_mac_pcs_get_fec_bypass(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_field_fec_stat_bypass);
+}
+
+bool nthw_mac_pcs_get_fec_valid(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_field_fec_stat_valid);
+}
+
+bool nthw_mac_pcs_get_fec_stat_all_am_locked(nthw_mac_pcs_t *p)
+{
+ nthw_register_update(p->mp_reg_fec_stat);
+
+ if ((nthw_field_get_val32(p->mp_field_fec_stat_am_lock0)) &&
+ (nthw_field_get_val32(p->mp_field_fec_stat_am_lock1)) &&
+ (nthw_field_get_val32(p->mp_field_fec_stat_am_lock2)) &&
+ (nthw_field_get_val32(p->mp_field_fec_stat_am_lock3))) {
+ return true;
+ }
+
+ return false;
+}
+
+void nthw_mac_pcs_reset_fec_counters(nthw_mac_pcs_t *p)
+{
+ nthw_register_update(p->mp_reg_fec_cw_cnt);
+ nthw_register_update(p->mp_reg_fec_ucw_cnt);
+
+ if (nthw_field_get_val32(p->mp_field_fec_cw_cnt_cw_cnt)) {
+ NT_LOG(DBG, NTHW, "Port %u: FEC_CW_CNT: %u\n", p->m_port_no,
+ nthw_field_get_val32(p->mp_field_fec_cw_cnt_cw_cnt));
+ }
+
+ if (nthw_field_get_val32(p->mp_field_fec_ucw_cnt_ucw_cnt)) {
+ NT_LOG(DBG, NTHW, "Port %u: FEC_UCW_CNT: %u\n", p->m_port_no,
+ nthw_field_get_val32(p->mp_field_fec_ucw_cnt_ucw_cnt));
+ }
+}
+
+void nthw_mac_pcs_set_gty_tx_tuning(nthw_mac_pcs_t *p, uint8_t lane, uint8_t tx_pre_csr,
+ uint8_t tx_diff_ctl, uint8_t tx_post_csr)
+{
+ /* GTY_PRE_CURSOR */
+ nthw_register_update(p->mp_reg_gty_pre_cursor);
+
+ switch (lane) {
+ case 0:
+ nthw_field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr0,
+ tx_pre_csr & 0x1F);
+ break;
+
+ case 1:
+ nthw_field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr1,
+ tx_pre_csr & 0x1F);
+ break;
+
+ case 2:
+ nthw_field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr2,
+ tx_pre_csr & 0x1F);
+ break;
+
+ case 3:
+ nthw_field_set_val_flush32(p->mp_field_gty_pre_cursor_tx_pre_csr3,
+ tx_pre_csr & 0x1F);
+ break;
+ }
+
+ /* GTY_DIFF_CTL */
+ nthw_register_update(p->mp_reg_gty_diff_ctl);
+
+ switch (lane) {
+ case 0:
+ nthw_field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl0,
+ tx_diff_ctl & 0x1F);
+ break;
+
+ case 1:
+ nthw_field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl1,
+ tx_diff_ctl & 0x1F);
+ break;
+
+ case 2:
+ nthw_field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl2,
+ tx_diff_ctl & 0x1F);
+ break;
+
+ case 3:
+ nthw_field_set_val_flush32(p->mp_field_gty_gty_diff_ctl_tx_diff_ctl3,
+ tx_diff_ctl & 0x1F);
+ break;
+ }
+
+ /* GTY_POST_CURSOR */
+ nthw_register_update(p->mp_reg_gty_post_cursor);
+
+ switch (lane) {
+ case 0:
+ nthw_field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr0,
+ tx_post_csr & 0x1F);
+ break;
+
+ case 1:
+ nthw_field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr1,
+ tx_post_csr & 0x1F);
+ break;
+
+ case 2:
+ nthw_field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr2,
+ tx_post_csr & 0x1F);
+ break;
+
+ case 3:
+ nthw_field_set_val_flush32(p->mp_field_gty_post_cursor_tx_post_csr3,
+ tx_post_csr & 0x1F);
+ break;
+ }
+
+ NT_LOG(DBG, NTHW,
+ "Port %u, lane %u: GTY tx_pre_csr: %d, tx_diff_ctl: %d, tx_post_csr: %d\n",
+ p->m_port_no, lane, tx_pre_csr, tx_diff_ctl, tx_post_csr);
+}
+
+/*
+ * Set receiver equalization mode
+ * 0: enable DFE
+ * 1: enable LPM
+ *
+ * See UltraScale Architecture GTY Transceivers www.xilinx.com page 181,
+ * UG578 (v1.1) November 24, 2015
+ */
+void nthw_mac_pcs_set_receiver_equalization_mode(nthw_mac_pcs_t *p, uint8_t mode)
+{
+ nthw_register_update(p->mp_reg_gty_ctl);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_lpm_en0, mode & 0x1);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_lpm_en1, mode & 0x1);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_lpm_en2, mode & 0x1);
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_lpm_en3, mode & 0x1);
+
+ /* Toggle reset */
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst0, 1);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst1, 1);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst2, 1);
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_equa_rst3, 1);
+
+ nt_os_wait_usec(1000); /* 1ms */
+
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst0, 0);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst1, 0);
+ nthw_field_set_val32(p->mp_field_gty_ctl_rx_equa_rst2, 0);
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_equa_rst3, 0);
+
+ NT_LOG(DBG, NTHW, "Port %u: GTY receiver mode: %s\n", p->m_port_no,
+ (mode == c_mac_pcs_receiver_mode_dfe ? "DFE" : "LPM"));
+}
+
+void nthw_mac_pcs_swap_gty_tx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap)
+{
+ nthw_register_update(p->mp_reg_gty_ctl);
+
+ switch (lane) {
+ case 0:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_tx_pol0, swap);
+ break;
+
+ case 1:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_tx_pol1, swap);
+ break;
+
+ case 2:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_tx_pol2, swap);
+ break;
+
+ case 3:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_tx_pol3, swap);
+ break;
+ }
+
+ NT_LOG(DBG, NTHW, "Port %u: set GTY Tx lane (%d) polarity: %d\n", p->m_port_no, lane,
+ swap);
+}
+
+void nthw_mac_pcs_swap_gty_rx_polarity(nthw_mac_pcs_t *p, uint8_t lane, bool swap)
+{
+ nthw_register_update(p->mp_reg_gty_ctl);
+
+ switch (lane) {
+ case 0:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_pol0, swap);
+ break;
+
+ case 1:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_pol1, swap);
+ break;
+
+ case 2:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_pol2, swap);
+ break;
+
+ case 3:
+ nthw_field_set_val_flush32(p->mp_field_gty_ctl_rx_pol3, swap);
+ break;
+ }
+
+ NT_LOG(DBG, NTHW, "Port %u: set GTY Rx lane (%d) polarity: %d\n", p->m_port_no, lane,
+ swap);
+}
+
+void nthw_mac_pcs_set_led_mode(nthw_mac_pcs_t *p, uint8_t mode)
+{
+ nthw_field_get_updated(p->mp_field_debounce_ctrl_nt_port_ctrl);
+ nthw_field_set_val_flush32(p->mp_field_debounce_ctrl_nt_port_ctrl, mode);
+}
+
+void nthw_mac_pcs_set_timestamp_comp_rx(nthw_mac_pcs_t *p, uint16_t rx_dly)
+{
+ if (p->mp_field_time_stamp_comp_rx_dly) {
+ nthw_field_get_updated(p->mp_field_time_stamp_comp_rx_dly);
+ nthw_field_set_val_flush32(p->mp_field_time_stamp_comp_rx_dly, rx_dly);
+ }
+}
+
+void nthw_mac_pcs_set_port_no(nthw_mac_pcs_t *p, uint8_t port_no)
+{
+ p->m_port_no = port_no;
+}
+
+uint32_t nthw_mac_pcs_get_fld_block_lock_lock(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_fld_block_lock_lock);
+}
+
+uint32_t nthw_mac_pcs_get_fld_block_lock_lock_mask(nthw_mac_pcs_t *p)
+{
+ return p->m_fld_block_lock_lock_mask;
+}
+
+uint32_t nthw_mac_pcs_get_fld_lane_lock_lock(nthw_mac_pcs_t *p)
+{
+ return nthw_field_get_updated(p->mp_fld_vl_demuxed_lock);
+}
+
+uint32_t nthw_mac_pcs_get_fld_lane_lock_lock_mask(nthw_mac_pcs_t *p)
+{
+ return p->m_fld_vl_demuxed_lock_mask;
+}