From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com,
stephen@networkplumber.org,
Danylo Vodopianov <dvo-plv@napatech.com>
Subject: [PATCH v1 25/32] net/ntnic: add SPI v3 support for FPGA
Date: Thu, 20 Feb 2025 23:03:49 +0100 [thread overview]
Message-ID: <20250220220406.3925597-26-sil-plv@napatech.com> (raw)
In-Reply-To: <20250220220406.3925597-1-sil-plv@napatech.com>
From: Danylo Vodopianov <dvo-plv@napatech.com>
- Implement nthw_spi_v3 module with initialization, transfer, and
utility functions.
- Add nthw_spim and nthw_spis modules for SPI primary and secondary
interfaces.
- Include SPI v3 header files and update meson build configuration.
- Implement AVR probe function to retrieve and log AVR information.
Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
drivers/net/ntnic/meson.build | 3 +
.../net/ntnic/nthw/core/include/nthw_fpga.h | 2 +
.../net/ntnic/nthw/core/include/nthw_spi_v3.h | 107 +++++
.../net/ntnic/nthw/core/include/nthw_spim.h | 58 +++
.../net/ntnic/nthw/core/include/nthw_spis.h | 63 +++
.../nt400dxx/reset/nthw_fpga_rst_nt400dxx.c | 2 +
drivers/net/ntnic/nthw/core/nthw_fpga.c | 444 ++++++++++++++++++
drivers/net/ntnic/nthw/core/nthw_spi_v3.c | 358 ++++++++++++++
drivers/net/ntnic/nthw/core/nthw_spim.c | 113 +++++
drivers/net/ntnic/nthw/core/nthw_spis.c | 121 +++++
10 files changed, 1271 insertions(+)
create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_spi_v3.h
create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_spim.h
create mode 100644 drivers/net/ntnic/nthw/core/include/nthw_spis.h
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
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 9885d4efbf..7e326a3e1d 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -69,6 +69,9 @@ sources = files(
'nthw/core/nthw_rmc.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/stat/nthw_stat.c',
'nthw/flow_api/flow_api.c',
'nthw/flow_api/flow_group.c',
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_fpga.h b/drivers/net/ntnic/nthw/core/include/nthw_fpga.h
index 8b1d548a25..418aea8277 100644
--- a/drivers/net/ntnic/nthw/core/include/nthw_fpga.h
+++ b/drivers/net/ntnic/nthw/core/include/nthw_fpga.h
@@ -18,6 +18,8 @@ int nthw_fpga_shutdown(struct fpga_info_s *p_fpga_info);
int nthw_fpga_get_param_info(struct fpga_info_s *p_fpga_info, nthw_fpga_t *p_fpga);
+int nthw_fpga_avr_probe(nthw_fpga_t *p_fpga, const int n_instance_no);
+
int nthw_fpga_iic_scan(nthw_fpga_t *p_fpga, const int n_instance_no_begin,
const int n_instance_no_end);
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_spi_v3.h b/drivers/net/ntnic/nthw/core/include/nthw_spi_v3.h
new file mode 100644
index 0000000000..66b1f7f45d
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_spi_v3.h
@@ -0,0 +1,107 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NT4GA_SPI_V3__
+#define __NT4GA_SPI_V3__
+
+#include "nthw_spis.h"
+#include "nthw_spim.h"
+
+/* Must include v1.x series. The first v1.0a only had 248 bytes of storage. v2.0x have 255 */
+#define MAX_AVR_CONTAINER_SIZE (248)
+
+enum avr_opcodes {
+ __AVR_OP_NOP = 0, /* v2 NOP command */
+ /* version handlers */
+ AVR_OP_VERSION = 1,
+ AVR_OP_SPI_VERSION = 2, /* v2.0+ command Get protocol version */
+ AVR_OP_SYSINFO = 3,
+ /* Ping handlers */
+ AVR_OP_PING = 4,
+ AVR_OP_PING_DELAY = 5,
+ /* i2c handlers */
+ AVR_OP_I2C_READ = 9,
+ AVR_OP_I2C_WRITE = 10,
+ AVR_OP_I2C_RANDOM_READ = 11,
+ /* VPD handlers */
+ AVR_OP_VPD_READ = 19,
+ AVR_OP_VPD_WRITE = 20,
+ /* SENSOR handlers */
+ AVR_OP_SENSOR_FETCH = 28,
+ /* The following command are only relevant to V3 */
+ AVR_OP_SENSOR_MON_CONTROL = 42,
+ AVR_OP_SENSOR_MON_SETUP = 43,
+ /* special version handler */
+ AVR_OP_SYSINFO_2 = 62,
+};
+
+#define GEN2_AVR_IDENT_SIZE (20)
+#define GEN2_AVR_VERSION_SIZE (50)
+
+#define GEN2_PN_SIZE (13)
+#define GEN2_PBA_SIZE (16)
+#define GEN2_SN_SIZE (10)
+#define GEN2_BNAME_SIZE (14)
+#define GEN2_PLATFORM_SIZE (72)
+#define GEN2_VPD_SIZE_TOTAL \
+ (1 + GEN2_PN_SIZE + GEN2_PBA_SIZE + GEN2_SN_SIZE + GEN2_BNAME_SIZE + GEN2_PLATFORM_SIZE + \
+ 2)
+
+typedef struct vpd_eeprom_s {
+ uint8_t psu_hw_version; /* Hw revision - MUST NEVER ne overwritten. */
+ /* Vital Product Data: P/N (13bytes ascii 0-9) */
+ uint8_t vpd_pn[GEN2_PN_SIZE];
+ /* Vital Product Data: PBA (16bytes ascii 0-9) */
+ uint8_t vpd_pba[GEN2_PBA_SIZE];
+ /* Vital Product Data: S/N (10bytes ascii 0-9) */
+ uint8_t vpd_sn[GEN2_SN_SIZE];
+ /* Vital Product Data: Board Name (10bytes ascii) (e.g. "ntmainb1e2" or "ntfront20b1") */
+ uint8_t vpd_board_name[GEN2_BNAME_SIZE];
+ /*
+ * Vital Product Data: Other (72bytes of MAC addresses or other stuff.. (gives up to 12 mac
+ * addresses)
+ */
+ uint8_t vpd_platform_section[GEN2_PLATFORM_SIZE];
+ /* CRC16 checksum of all of above. This field is not included in the checksum */
+ uint16_t crc16;
+} vpd_eeprom_t;
+
+typedef struct {
+ uint8_t psu_hw_revision;
+ char board_type[GEN2_BNAME_SIZE + 1];
+ char product_id[GEN2_PN_SIZE + 1];
+ char pba_id[GEN2_PBA_SIZE + 1];
+ char serial_number[GEN2_SN_SIZE + 1];
+ uint8_t product_family;
+ uint32_t feature_mask;
+ uint32_t invfeature_mask;
+ uint8_t no_of_macs;
+ uint8_t mac_address[6];
+ uint16_t custom_id;
+ uint8_t user_id[8];
+} board_info_t;
+
+struct tx_rx_buf {
+ uint16_t size;
+ void *p_buf;
+};
+
+struct nthw_spi_v3 {
+ int m_time_out;
+ int mn_instance_no;
+ nthw_spim_t *mp_spim_mod;
+ nthw_spis_t *mp_spis_mod;
+};
+
+typedef struct nthw_spi_v3 nthw_spi_v3_t;
+typedef struct nthw_spi_v3 nthw_spi_v3;
+
+nthw_spi_v3_t *nthw_spi_v3_new(void);
+int nthw_spi_v3_init(nthw_spi_v3_t *p, nthw_fpga_t *p_fpga, int n_instance_no);
+
+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);
+
+#endif /* __NT4GA_SPI_V3__ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_spim.h b/drivers/net/ntnic/nthw/core/include/nthw_spim.h
new file mode 100644
index 0000000000..70a49ab627
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_spim.h
@@ -0,0 +1,58 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_SPIM_H__
+#define __NTHW_SPIM_H__
+
+#include "nthw_fpga.h"
+
+struct nthw_spim {
+ nthw_fpga_t *mp_fpga;
+ nthw_module_t *mp_mod_spim;
+ int mn_instance;
+
+ nthw_register_t *mp_reg_srr;
+ nthw_field_t *mp_fld_srr_rst;
+
+ nthw_register_t *mp_reg_cr;
+ nthw_field_t *mp_fld_cr_loop;
+ nthw_field_t *mp_fld_cr_en;
+ nthw_field_t *mp_fld_cr_txrst;
+ nthw_field_t *mp_fld_cr_rxrst;
+
+ nthw_register_t *mp_reg_sr;
+ nthw_field_t *mp_fld_sr_done;
+ nthw_field_t *mp_fld_sr_txempty;
+ nthw_field_t *mp_fld_sr_rxempty;
+ nthw_field_t *mp_fld_sr_txfull;
+ nthw_field_t *mp_fld_sr_rxfull;
+ nthw_field_t *mp_fld_sr_txlvl;
+ nthw_field_t *mp_fld_sr_rxlvl;
+
+ nthw_register_t *mp_reg_dtr;
+ nthw_field_t *mp_fld_dtr_dtr;
+
+ nthw_register_t *mp_reg_drr;
+ nthw_field_t *mp_fld_drr_drr;
+
+ nthw_register_t *mp_reg_cfg;
+ nthw_field_t *mp_fld_cfg_pre;
+
+ nthw_register_t *mp_reg_cfg_clk;
+ nthw_field_t *mp_fld_cfg_clk_mode;
+};
+
+typedef struct nthw_spim nthw_spim_t;
+typedef struct nthw_spim nthw_spim;
+
+nthw_spim_t *nthw_spim_new(void);
+int nthw_spim_init(nthw_spim_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+uint32_t nthw_spim_reset(nthw_spim_t *p);
+uint32_t nthw_spim_enable(nthw_spim_t *p, bool b_enable);
+uint32_t nthw_spim_get_tx_fifo_empty(nthw_spim_t *p, bool *pb_empty);
+uint32_t nthw_spim_write_tx_fifo(nthw_spim_t *p, uint32_t n_data);
+
+#endif /* __NTHW_SPIM_H__ */
diff --git a/drivers/net/ntnic/nthw/core/include/nthw_spis.h b/drivers/net/ntnic/nthw/core/include/nthw_spis.h
new file mode 100644
index 0000000000..978f239dd0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/include/nthw_spis.h
@@ -0,0 +1,63 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#ifndef __NTHW_SPIS_H__
+#define __NTHW_SPIS_H__
+
+#include "nthw_fpga.h"
+
+struct nthw_spis {
+ nthw_fpga_t *mp_fpga;
+ nthw_module_t *mp_mod_spis;
+ int mn_instance;
+
+ nthw_register_t *mp_reg_srr;
+ nthw_field_t *mp_fld_srr_rst;
+
+ nthw_register_t *mp_reg_cr;
+ nthw_field_t *mp_fld_cr_loop;
+ nthw_field_t *mp_fld_cr_en;
+ nthw_field_t *mp_fld_cr_txrst;
+ nthw_field_t *mp_fld_cr_rxrst;
+ nthw_field_t *mp_fld_cr_debug;
+
+ nthw_register_t *mp_reg_sr;
+ nthw_field_t *mp_fld_sr_done;
+ nthw_field_t *mp_fld_sr_txempty;
+ nthw_field_t *mp_fld_sr_rxempty;
+ nthw_field_t *mp_fld_sr_txfull;
+ nthw_field_t *mp_fld_sr_rxfull;
+ nthw_field_t *mp_fld_sr_txlvl;
+ nthw_field_t *mp_fld_sr_rxlvl;
+ nthw_field_t *mp_fld_sr_frame_err;
+ nthw_field_t *mp_fld_sr_read_err;
+ nthw_field_t *mp_fld_sr_write_err;
+
+ nthw_register_t *mp_reg_dtr;
+ nthw_field_t *mp_fld_dtr_dtr;
+
+ nthw_register_t *mp_reg_drr;
+ nthw_field_t *mp_fld_drr_drr;
+
+ nthw_register_t *mp_reg_ram_ctrl;
+ nthw_field_t *mp_fld_ram_ctrl_adr;
+ nthw_field_t *mp_fld_ram_ctrl_cnt;
+
+ nthw_register_t *mp_reg_ram_data;
+ nthw_field_t *mp_fld_ram_data_data;
+};
+
+typedef struct nthw_spis nthw_spis_t;
+typedef struct nthw_spis nthw_spis;
+
+nthw_spis_t *nthw_spis_new(void);
+int nthw_spis_init(nthw_spis_t *p, nthw_fpga_t *p_fpga, int n_instance);
+
+uint32_t nthw_spis_reset(nthw_spis_t *p);
+uint32_t nthw_spis_enable(nthw_spis_t *p, bool b_enable);
+uint32_t nthw_spis_get_rx_fifo_empty(nthw_spis_t *p, bool *pb_empty);
+uint32_t nthw_spis_read_rx_fifo(nthw_spis_t *p, uint32_t *p_data);
+
+#endif /* __NTHW_SPIS_H__ */
diff --git a/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c b/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c
index ff29101e61..73feaa4ebd 100644
--- a/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c
+++ b/drivers/net/ntnic/nthw/core/nt400dxx/reset/nthw_fpga_rst_nt400dxx.c
@@ -65,6 +65,8 @@ static int nthw_fpga_rst_nt400dxx_init(struct fpga_info_s *p_fpga_info)
nthw_prm_nt400dxx_periph_rst(p_fpga_info->mp_nthw_agx.p_prm, 0);
nt_os_wait_usec(10000);
+ res = nthw_fpga_avr_probe(p_fpga, 0);
+
if (res != 0)
return res;
diff --git a/drivers/net/ntnic/nthw/core/nthw_fpga.c b/drivers/net/ntnic/nthw/core/nthw_fpga.c
index e54a210c9f..3166a2ba51 100644
--- a/drivers/net/ntnic/nthw/core/nthw_fpga.c
+++ b/drivers/net/ntnic/nthw/core/nthw_fpga.c
@@ -14,6 +14,7 @@
#include "nthw_fpga_mod_str_map.h"
#include "nthw_tsm.h"
+#include "nthw_spi_v3.h"
#include <arpa/inet.h>
@@ -151,6 +152,449 @@ int nthw_fpga_silabs_detect(nthw_fpga_t *p_fpga, const int n_instance_no, const
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", 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", 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'", 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'", 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",
+ 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",
+ 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", 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", 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", 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", 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", 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", 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", 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", 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)",
+ 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",
+ 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",
+ 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",
+ 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", 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",
+ 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", 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", p_adapter_id_str,
+ n_instance_no, avr_vpd_info.sysinfo_hw_revision);
+ NT_LOG(INF, NTHW, "%s: AVR%d: HW_REV: %d", 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",
+ 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", 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", 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)",
+ 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",
+ 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", 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", 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", 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'", 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'", 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", 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'", 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", 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",
+ 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",
+ 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", 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", 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",
+ 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 "",
+ 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", __func__, __LINE__, res);
+ NT_LOG(ERR, NTHW, "%s: AVR%d: SYSINFO2: NA: res=%d sz=%d",
+ p_adapter_id_str, n_instance_no, res, rx_buf.size);
+ }
+ }
+
+ return res;
+}
+
/*
* NT200A02, NT200A01-HWbuild2
*/
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..0b611462a0
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spi_v3.c
@@ -0,0 +1,358 @@
+/*
+ * 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;
+}
+
+static 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");
+ 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", __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");
+ 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", __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", 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", 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", 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", 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", 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(DBG, NTHW, "Started");
+#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");
+ 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");
+ 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", 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");
+ 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");
+ 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");
+ 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", __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");
+ 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",
+ 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");
+ 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", rx_buf->size);
+ dump_hex(rx_buf->p_buf, rx_buf->size);
+ NT_LOG(DBG, NTHW, "%s: Ended: %d", __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..d30c11d0ff
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spim.c
@@ -0,0 +1,113 @@
+/*
+ * 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", 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;
+}
+
+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..3c34dec936
--- /dev/null
+++ b/drivers/net/ntnic/nthw/core/nthw_spis.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_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", 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;
+}
+
+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;
+}
--
2.45.0
next prev parent reply other threads:[~2025-02-20 22:07 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-20 22:03 [PATCH v1 00/32] add new adapter NT400D13 Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 01/32] net/ntnic: add link agx 100g Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 02/32] net/ntnic: add link state machine Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 03/32] net/ntnic: add rpf and gfg init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 04/32] net/ntnic: add agx setup for port Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 05/32] net/ntnic: add host loopback init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 06/32] net/ntnic: add line " Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 07/32] net/ntnic: add 100 gbps port init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 08/32] net/ntnic: add port post init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 09/32] net/ntnic: add nim low power API Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 10/32] net/ntnic: add link handling API Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 11/32] net/ntnic: add port init to the state machine Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 12/32] net/ntnic: add port disable API Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 13/32] net/ntnic: add minimal initialization new NIC NT400D13 Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 14/32] net/ntnic: add minimal reset FPGA Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 15/32] net/ntnic: add FPGA modules and registers Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 16/32] net/ntnic: add setup for fpga reset Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 17/32] net/ntnic: add default reset setting for NT400D13 Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 18/32] net/ntnic: add DDR calibration to reset stage Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 19/32] net/ntnic: add PHY ftile reset Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 20/32] net/ntnic: add clock init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 21/32] net/ntnic: add nt400d13 pcm init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 22/32] net/ntnic: add HIF clock test Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 23/32] net/ntnic: add nt400d13 PRM module init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 24/32] net/ntnic: add nt400d13 PRM module reset Serhii Iliushyk
2025-02-20 22:03 ` Serhii Iliushyk [this message]
2025-02-20 22:03 ` [PATCH v1 26/32] net/ntnic: add i2cm init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 27/32] net/ntnic: add pca init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 28/32] net/ntnic: add pcal init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 29/32] net/ntnic: add reset PHY init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 30/32] net/ntnic: add igam module init Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 31/32] net/ntnic: init IGAM and config PLL for FPGA Serhii Iliushyk
2025-02-20 22:03 ` [PATCH v1 32/32] net/ntnic: revert untrusted loop bound Serhii Iliushyk
2025-02-20 22:31 ` Stephen Hemminger
2025-02-20 23:49 ` [PATCH v1 00/32] add new adapter NT400D13 Stephen Hemminger
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=20250220220406.3925597-26-sil-plv@napatech.com \
--to=sil-plv@napatech.com \
--cc=ckm@napatech.com \
--cc=dev@dpdk.org \
--cc=dvo-plv@napatech.com \
--cc=mko-plv@napatech.com \
--cc=stephen@networkplumber.org \
/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).