fpga: x400: Add support for X410 motherboard FPGA

Co-authored-by: Andrew Moch <Andrew.Moch@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Javier Valenzuela <javier.valenzuela@ni.com>
Co-authored-by: Joerg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Kumaran Subramoniam <kumaran.subramoniam@ni.com>
Co-authored-by: Max Köhler <max.koehler@ni.com>
Co-authored-by: Michael Auchter <michael.auchter@ni.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Co-authored-by: Hector Rubio <hrubio@ni.com>


Original-commit: 6d3765605262016a80f71e36357f749ea35cbe5a
This commit is contained in:
Wade Fife
2021-06-10 11:56:58 -05:00
committed by Aaron Rossetto
co-authored by Andrew Moch Daniel Jepson Javier Valenzuela Joerg Hofrichter Kumaran Subramoniam Max Köhler Michael Auchter Paul Butler Hector Rubio
parent bfef20ea45
commit 61782b02d7
205 changed files with 299634 additions and 0 deletions
+423
View File
@@ -0,0 +1,423 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: x4xx_mgt_io_core
//
// Description:
//
// Encapsulates the PCS/PMA, the MAC layer and the control interface
// for 10GbE, and 100Gbe.
//
// Parameters:
//
// PROTOCOL : Indicates the protocol to use for each of the 4 QSFP lanes.
// See x4xx_mgt_types.vh for possible values.
// REG_BASE : Base address for internal registers
// REG_DWIDTH : Register data width
// REG_AWIDTH : Register address width
// PORTNUM : Port number, to distinguish between multiple QSFP ports
// LANENUM : Lane number
//
`include "./x4xx_mgt_types.vh"
module x4xx_mgt_io_core #(
parameter PROTOCOL = `MGT_100GbE,
parameter [13:0] REG_BASE = 14'h0,
parameter REG_DWIDTH = 32,
parameter REG_AWIDTH = 14,
parameter [ 7:0] PORTNUM = 8'd0,
parameter LANENUM = 0
) (
// Resets
input logic areset,
input logic bus_rst,
output logic mgt_rst,
// Clocks
input logic clk100,
input logic bus_clk,
input logic refclk_p,
input logic refclk_n,
output logic mgt_clk,
// QSFP high-speed IO
output logic [3:0] tx_p,
output logic [3:0] tx_n,
input logic [3:0] rx_p,
input logic [3:0] rx_n,
// Common signals for single lane 10 GbE
output logic [0:0] qpll0_reset,
input logic [0:0] qpll0_lock,
input logic [0:0] qpll0_clk,
input logic [0:0] qpll0_refclk,
output logic [0:0] qpll1_reset,
input logic [0:0] qpll1_lock,
input logic [0:0] qpll1_clk,
input logic [0:0] qpll1_refclk,
// AXI-Lite
AxiLiteIf.slave m_axi_mac,
// Data port
// Interface clocks on mgt_tx and mgt_rx are NOT used (logic uses mgt_clk).
AxiStreamIf.slave mgt_tx,
AxiStreamIf.master mgt_rx,
input logic mgt_pause_req,
// Register port
input logic reg_wr_req,
input logic [REG_AWIDTH-1:0] reg_wr_addr,
input logic [REG_DWIDTH-1:0] reg_wr_data,
input logic reg_rd_req,
input logic [REG_AWIDTH-1:0] reg_rd_addr,
output logic reg_rd_resp,
output logic [REG_DWIDTH-1:0] reg_rd_data,
// Misc.
output logic rx_rec_clk_out,
output logic [31:0] port_info,
output logic link_up,
output logic activity
);
import PkgAxiLite::*;
//---------------------------------------------------------------------------
// Registers
//---------------------------------------------------------------------------
localparam [7:0] COMPAT_NUM = 8'd2;
// Common registers
localparam REG_PORT_INFO = REG_BASE + 'h0;
localparam REG_MAC_CTRL_STATUS = REG_BASE + 'h4;
localparam REG_PHY_CTRL_STATUS = REG_BASE + 'h8;
localparam REG_MAC_LED_CTL = REG_BASE + 'hC;
// Ethernet specific
localparam REG_ETH_MDIO_BASE = REG_BASE + 'h10;
// Aurora specific
localparam REG_AURORA_OVERRUNS = REG_BASE + 'h20;
localparam REG_CHECKSUM_ERRORS = REG_BASE + 'h24;
localparam REG_BIST_CHECKER_SAMPS = REG_BASE + 'h28;
localparam REG_BIST_CHECKER_ERRORS = REG_BASE + 'h2C;
localparam [ 1:0] MAC_LED_CTRL_RST_VAL = 2'h0;
localparam [ 7:0] MGT_PROTOCOL = PROTOCOL;
localparam [31:0] MAC_CTRL_RST_VAL =
PROTOCOL == `MGT_100GbE ? {31'h0, 1'b1} : // Auto-connect enabled by default
PROTOCOL == `MGT_WhiteRabbit ? 32'h0 :
PROTOCOL == `MGT_Aurora ? 32'h0 :
PROTOCOL == `MGT_10GbE ? {31'h0, 1'b1} : // Tx enabled by default
PROTOCOL == `MGT_1GbE ? {31'h0, 1'b1} : // Tx enabled by default
32'h0;
localparam [31:0] PHY_CTRL_RST_VAL =
PROTOCOL == `MGT_100GbE ? 32'h0 : // Unused
PROTOCOL == `MGT_WhiteRabbit ? 32'h0 : // Unused
PROTOCOL == `MGT_Aurora ? 32'h0 :
PROTOCOL == `MGT_10GbE ? 32'h0 : // Unused
PROTOCOL == `MGT_1GbE ? 32'h0 :
32'h0;
// Writable registers
logic [31:0] mac_ctrl = MAC_CTRL_RST_VAL;
logic [31:0] phy_ctrl = PHY_CTRL_RST_VAL;
logic [ 1:0] mac_led_ctl = MAC_LED_CTRL_RST_VAL;
always @(posedge bus_clk) begin
if (bus_rst) begin
mac_ctrl <= MAC_CTRL_RST_VAL;
phy_ctrl <= PHY_CTRL_RST_VAL;
mac_led_ctl <= MAC_LED_CTRL_RST_VAL;
end else if (reg_wr_req) begin
case(reg_wr_addr)
REG_MAC_CTRL_STATUS:
mac_ctrl <= reg_wr_data;
REG_PHY_CTRL_STATUS:
phy_ctrl <= reg_wr_data;
REG_MAC_LED_CTL:
mac_led_ctl <= reg_wr_data[1:0];
endcase
end
end
// Readable registers
logic [31:0] overruns;
logic [31:0] checksum_errors;
logic [47:0] bist_checker_samps;
logic [47:0] bist_checker_errors;
logic [31:0] mac_status, phy_status;
logic [31:0] mac_status_bclk, phy_status_bclk;
logic activity_bclk, link_up_bclk;
assign port_info = {COMPAT_NUM, 6'h0, activity_bclk, link_up_bclk, MGT_PROTOCOL, PORTNUM};
always @(posedge bus_clk) begin
// No reset handling needed for readback
if (reg_rd_req) begin
reg_rd_resp <= 1'b1;
case(reg_rd_addr)
REG_PORT_INFO:
reg_rd_data <= port_info;
REG_MAC_CTRL_STATUS:
reg_rd_data <= mac_status_bclk;
REG_PHY_CTRL_STATUS:
reg_rd_data <= phy_status_bclk;
REG_MAC_LED_CTL:
reg_rd_data <= {30'd0, mac_led_ctl};
REG_AURORA_OVERRUNS:
reg_rd_data <= overruns;
REG_CHECKSUM_ERRORS:
reg_rd_data <= checksum_errors;
REG_BIST_CHECKER_SAMPS:
reg_rd_data <= bist_checker_samps[47:16]; // Scale num samples by 2^16
REG_BIST_CHECKER_ERRORS:
reg_rd_data <= bist_checker_errors[31:0]; // Don't scale errors
default:
begin
reg_rd_data <= 32'd0;
reg_rd_resp <= 1'b0;
end
endcase
end if (reg_rd_resp) begin
reg_rd_resp <= 1'b0;
end
end
synchronizer #(
.STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0)
) synchronizer_mac_status (
.clk(bus_clk), .rst(1'b0), .in(mac_status), .out(mac_status_bclk)
);
synchronizer #(
.STAGES(2), .WIDTH(32), .INITIAL_VAL(32'h0)
) synchronizer_phy_status (
.clk(bus_clk), .rst(1'b0), .in(phy_status), .out(phy_status_bclk)
);
logic link_up_mgtclk;
logic wr_activity = 0;
if (PROTOCOL == `MGT_10GbE) begin : core_10g
//-------------------------------------------------------------------------
// 10 GbE Interface
//-------------------------------------------------------------------------
eth_10g eth_10g_i (
.areset (areset),
// Free-running 100 MHz clock used for InitClk and AxiLite to MAC
.clk100 (clk100),
// Quad Info
.qpll0_refclk (qpll0_refclk),
.qpll0_clk (qpll0_clk),
.qpll0_lock (qpll0_lock),
.qpll0_reset (qpll0_reset),
.qpll1_refclk (qpll1_refclk),
.qpll1_clk (qpll1_clk),
.qpll1_lock (qpll1_lock),
.qpll1_reset (qpll1_reset),
// Recovered clock for export
.rx_rec_clk_out (rx_rec_clk_out),
// MGT TX/RX differential signals
.tx_p (tx_p[LANENUM]),
.tx_n (tx_n[LANENUM]),
.rx_p (rx_p[LANENUM]),
.rx_n (rx_n[LANENUM]),
// 156.25 MHz clock
.mgt_clk (mgt_clk),
.mgt_rst (mgt_rst),
// AXI Stream TX Interface
.mgt_tx (mgt_tx),
// AXI Stream RX Interface
// There is no RX TREADY signal support in the IP. Received data has to
// be read immediately or it is lost. TUSER indicates an error on
// received packet.
.mgt_rx (mgt_rx),
// AXI-Lite bus for tie off
.mgt_axil (m_axi_mac),
// LEDs of QSFP28 port
.phy_status (phy_status),
.mac_ctrl (mac_ctrl),
.mac_status (mac_status),
.phy_reset (),
.link_up (link_up_mgtclk)
);
always_comb begin : eth_10g_tieoff
overruns = 0;
checksum_errors = 0;
bist_checker_samps = 0;
bist_checker_errors = 0;
end : eth_10g_tieoff
end else if (PROTOCOL == `MGT_100GbE) begin : core_100g
//-------------------------------------------------------------------------
// 100 GbE Interface
//-------------------------------------------------------------------------
eth_100g eth_100g_i (
.areset (areset),
// Free-running 100 MHz clock used for InitClk and AxiLite to MAC
.clk100 (clk100),
// MGT Reference Clock 100/125/156.25/161.1328125 MHz
.refclk_p (refclk_p),
.refclk_n (refclk_n),
// Recovered clock for export
.rx_rec_clk_out (rx_rec_clk_out),
// MGT TX/RX differential signals
.tx_p (tx_p),
.tx_n (tx_n),
.rx_p (rx_p),
.rx_n (rx_n),
// 322.26666 MHz clock generated by 100G PHY from RefClock
.mgt_clk (mgt_clk),
.mgt_rst (mgt_rst),
.mgt_pause_req (mgt_pause_req),
// AXI Stream TX Interface
.mgt_tx (mgt_tx),
// AXI Stream RX Interface
// There is no RX TREADY signal support in the IP. Received data has to
// be read immediately or it is lost. TUSER indicates an error on
// received packet.
.mgt_rx (mgt_rx),
.mgt_axil (m_axi_mac),
// LEDs of QSFP28 port
.phy_status (phy_status),
.mac_status (mac_status),
.mac_ctrl (mac_ctrl),
.phy_reset (),
.link_up (link_up_mgtclk)
);
always_comb begin : eth_100g_tieoff
overruns = 0;
checksum_errors = 0;
bist_checker_samps = 0;
bist_checker_errors = 0;
qpll0_reset = 0;
qpll1_reset = 0;
end : eth_100g_tieoff
end else if (PROTOCOL == `MGT_Aurora) begin : core_aurora
Aurora_not_yet_supported();
always_comb begin : aurrora_tieoff
m_axi_mac.drive_read_resp(.resp(SLVERR),.data(0));
m_axi_mac.drive_write_resp(.resp(SLVERR));
m_axi_mac.arready = 1'b1;
m_axi_mac.awready = 1'b1;
m_axi_mac.wready = 1'b1;
phy_status = 'h0;
mac_status = 'h0;
link_up_mgtclk = 1'b0;
overruns = 0;
checksum_errors = 0;
bist_checker_samps = 0;
bist_checker_errors = 0;
rx_rec_clk_out = 0;
qpll0_reset = 0;
qpll1_reset = 0;
end : aurrora_tieoff
end else begin : core_disabled
//-------------------------------------------------------------------------
// Port Disabled
//-------------------------------------------------------------------------
assign mgt_clk = bus_clk;
assign mgt_rst = bus_rst;
always_comb begin : disabled_tieoff
m_axi_mac.drive_read_resp(.resp(SLVERR),.data(0));
m_axi_mac.drive_write_resp(.resp(SLVERR));
m_axi_mac.arready = 1'b1;
m_axi_mac.awready = 1'b1;
m_axi_mac.wready = 1'b1;
phy_status = 'h0;
mac_status = 'h0;
link_up_mgtclk = 1'b0;
mgt_tx.tready = 1'b1;
mgt_rx.tdata = 64'h0;
mgt_rx.tuser = 4'h0;
mgt_rx.tlast = 1'b0;
mgt_rx.tvalid = 1'b0;
mgt_rx.tkeep = 'b0;
overruns = 0;
checksum_errors = 0;
bist_checker_samps = 0;
bist_checker_errors = 0;
rx_rec_clk_out = 0;
tx_p = 0;
tx_n = 0;
qpll0_reset = 0;
qpll1_reset = 0;
end : disabled_tieoff
end
//---------------------------------------------------------------------------
// Activity Detector
//---------------------------------------------------------------------------
logic identify_enable,identify_value;
logic activity_mgtclk, activity_int;
always_comb begin
identify_enable = mac_led_ctl[0];
identify_value = mac_led_ctl[1];
end
pulse_stretch pulse_stretch_activity_i (
.clk (mgt_clk),
.rst (mgt_rst | ~link_up_mgtclk),
.pulse ((mgt_tx.tvalid & mgt_tx.tready) | (mgt_rx.tvalid & mgt_rx.tready)),
.pulse_stretched (activity_mgtclk)
);
synchronizer #(
.WIDTH (2),
.STAGES (1)
) synchronizer_lnk_act_bclk (
.clk (bus_clk),
.rst (bus_rst),
.in ({link_up_mgtclk, activity_mgtclk}),
.out ({link_up_bclk, activity_int})
);
always @ (posedge bus_clk) begin
activity_bclk <= identify_enable ? identify_value : activity_int;
end
synchronizer #(
.WIDTH (2),
.STAGES (1)
) synchronizer_lnk_act_aclk (
.clk (m_axi_mac.clk),
.rst (m_axi_mac.rst),
.in ({link_up_bclk, activity_bclk}),
.out ({link_up, activity})
);
endmodule