diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g.f b/src/eth/rtl/taxi_eth_mac_phy_10g.f index 90baa47..21a0c2b 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g.f +++ b/src/eth/rtl/taxi_eth_mac_phy_10g.f @@ -1,6 +1,7 @@ taxi_eth_mac_phy_10g.sv taxi_eth_mac_phy_10g_rx.f taxi_eth_mac_phy_10g_tx.f +taxi_eth_phy_10g_usxgmii_an.sv taxi_eth_mac_stats.f taxi_mac_ctrl_tx.sv taxi_mac_ctrl_rx.sv diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g.sv b/src/eth/rtl/taxi_eth_mac_phy_10g.sv index 114cc7e..06ff976 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g.sv @@ -21,6 +21,7 @@ module taxi_eth_mac_phy_10g # parameter HDR_W = (DATA_W/32), parameter logic TX_GBX_IF_EN = 1'b0, parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, + parameter logic USXGMII_EN = 1'b0, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -79,6 +80,27 @@ module taxi_eth_mac_phy_10g # output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, + /* + * USXGMII autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + input wire logic an_timeout_en = 1'b1, + input wire logic an_usxgmii_en = 1'b0, + input wire logic an_usxgmii_auto = 1'b1, + input wire logic an_usxgmii_5g = 1'b0, + output wire logic an_intr, + output wire logic an_running, + output wire logic an_complete, + output wire logic an_timeout, + output wire logic an_usxgmii_mode, + input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601, + output wire logic [15:0] an_lp_adv_ability, + output wire logic an_lp_usxgmii_link, + output wire logic [2:0] an_lp_usxgmii_speed, + output wire logic an_res_full_duplex, + /* * PTP */ @@ -356,10 +378,149 @@ end else begin end +// USXGMII autonegotiation +wire [23:0] rx_os; +wire rx_os_sig; +wire rx_os_valid; +wire rx_os_match; +wire rx_idle_match; + +wire [23:0] tx_os; +wire tx_os_sig; +wire tx_os_valid; +wire tx_os_ready; + +wire cfg_rx_usxgmii_en; +wire cfg_rx_usxgmii_5g; +wire [2:0] cfg_rx_usxgmii_speed; + +wire cfg_tx_usxgmii_en; +wire cfg_tx_usxgmii_5g; +wire [2:0] cfg_tx_usxgmii_speed; + +if (USXGMII_EN) begin : an + + // synchronize RX signals to TX + wire [23:0] sync_rx_os; + wire sync_rx_os_sig; + wire sync_rx_os_valid; + wire sync_rx_os_match; + wire sync_rx_idle_match; + wire sync_rx_block_lock; + + taxi_sync_signal #( + .WIDTH(24+5), + .N(2) + ) + rx_sync_inst ( + .clk(tx_clk), + + .in({ + rx_os, + rx_os_sig, + rx_os_valid, + rx_os_match, + rx_idle_match, + rx_block_lock + }), + .out({ + sync_rx_os, + sync_rx_os_sig, + sync_rx_os_valid, + sync_rx_os_match, + sync_rx_idle_match, + sync_rx_block_lock + }) + ); + + taxi_sync_signal #( + .WIDTH(1+1+3), + .N(2) + ) + rx_sync_ctrl_inst ( + .clk(rx_clk), + + .in({ + cfg_tx_usxgmii_en, + cfg_tx_usxgmii_5g, + cfg_tx_usxgmii_speed + }), + .out({ + cfg_rx_usxgmii_en, + cfg_rx_usxgmii_5g, + cfg_rx_usxgmii_speed + }) + ); + + taxi_eth_phy_10g_usxgmii_an #( + .DATA_W(DATA_W) + ) + an_inst ( + .clk(tx_clk), + .rst(tx_rst), + + /* + * Ordered sets + */ + .rx_os(sync_rx_os), + .rx_os_sig(sync_rx_os_sig), + .rx_os_valid(sync_rx_os_valid), + .rx_os_match(sync_rx_os_match), + .rx_idle_match(sync_rx_idle_match), + .rx_block_lock(sync_rx_block_lock), + + .tx_os(tx_os), + .tx_os_sig(tx_os_sig), + .tx_os_valid(tx_os_valid), + .tx_os_ready(tx_os_ready), + + /* + * USXGMII Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_usxgmii_5g(an_usxgmii_5g), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex) + ); + + assign cfg_tx_usxgmii_en = an_usxgmii_mode; + assign cfg_tx_usxgmii_5g = an_usxgmii_5g; + assign cfg_tx_usxgmii_speed = an_lp_usxgmii_speed; + +end else begin : an + + wire [23:0] tx_os = '0; + wire tx_os_sig = 1'b0; + wire tx_os_valid = 1'b0; + + wire cfg_rx_usxgmii_en = 1'b0; + wire cfg_rx_usxgmii_5g = 1'b0; + wire [2:0] cfg_rx_usxgmii_speed = 3'b011; + + wire cfg_tx_usxgmii_en = 1'b0; + wire cfg_tx_usxgmii_5g = 1'b0; + wire [2:0] cfg_tx_usxgmii_speed = 3'b011; + +end + taxi_eth_mac_phy_10g_rx #( .DATA_W(DATA_W), .HDR_W(HDR_W), .GBX_IF_EN(RX_GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W), @@ -390,6 +551,15 @@ eth_mac_phy_10g_rx_inst ( .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * Ordered sets + */ + .rx_os(rx_os), + .rx_os_sig(rx_os_sig), + .rx_os_valid(rx_os_valid), + .rx_os_match(rx_os_match), + .rx_idle_match(rx_idle_match), + /* * PTP */ @@ -424,6 +594,9 @@ eth_mac_phy_10g_rx_inst ( */ .cfg_rx_max_pkt_len(cfg_rx_max_pkt_len), .cfg_rx_enable(cfg_rx_enable), + .cfg_rx_usxgmii_en(cfg_rx_usxgmii_en), + .cfg_rx_usxgmii_5g(cfg_rx_usxgmii_5g), + .cfg_rx_usxgmii_speed(cfg_rx_usxgmii_speed), .cfg_rx_prbs31_enable(cfg_rx_prbs31_enable) ); @@ -431,6 +604,7 @@ taxi_eth_mac_phy_10g_tx #( .DATA_W(DATA_W), .HDR_W(HDR_W), .GBX_IF_EN(TX_GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), @@ -462,6 +636,14 @@ eth_mac_phy_10g_tx_inst ( .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), .serdes_tx_gbx_sync(serdes_tx_gbx_sync), + /* + * Ordered sets + */ + .tx_os(tx_os), + .tx_os_sig(tx_os_sig), + .tx_os_valid(tx_os_valid), + .tx_os_ready(tx_os_ready), + /* * PTP */ @@ -492,6 +674,9 @@ eth_mac_phy_10g_tx_inst ( .cfg_tx_max_pkt_len(cfg_tx_max_pkt_len), .cfg_tx_ifg(cfg_tx_ifg), .cfg_tx_enable(cfg_tx_enable), + .cfg_tx_usxgmii_en(cfg_tx_usxgmii_en), + .cfg_tx_usxgmii_5g(cfg_tx_usxgmii_5g), + .cfg_tx_usxgmii_speed(cfg_tx_usxgmii_speed), .cfg_tx_prbs31_enable(cfg_tx_prbs31_enable) ); diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv index 8c99ee8..50a3180 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_fifo.sv @@ -21,6 +21,7 @@ module taxi_eth_mac_phy_10g_fifo # parameter HDR_W = (DATA_W/32), parameter logic TX_GBX_IF_EN = 1'b0, parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, + parameter logic USXGMII_EN = 1'b0, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -92,6 +93,27 @@ module taxi_eth_mac_phy_10g_fifo # output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, + /* + * USXGMII autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + input wire logic an_timeout_en = 1'b1, + input wire logic an_usxgmii_en = 1'b0, + input wire logic an_usxgmii_auto = 1'b1, + input wire logic an_usxgmii_5g = 1'b0, + output wire logic an_intr, + output wire logic an_running, + output wire logic an_complete, + output wire logic an_timeout, + output wire logic an_usxgmii_mode, + input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601, + output wire logic [15:0] an_lp_adv_ability, + output wire logic an_lp_usxgmii_link, + output wire logic [2:0] an_lp_usxgmii_speed, + output wire logic an_res_full_duplex, + /* * PTP clock */ @@ -300,6 +322,7 @@ taxi_eth_mac_phy_10g #( .HDR_W(HDR_W), .TX_GBX_IF_EN(TX_GBX_IF_EN), .RX_GBX_IF_EN(RX_GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -356,6 +379,27 @@ eth_mac_phy_10g_inst ( .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * USXGMII autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_usxgmii_5g(an_usxgmii_5g), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex), + /* * PTP */ diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv index d89eba8..c287098 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_rx.sv @@ -20,6 +20,7 @@ module taxi_eth_mac_phy_10g_rx # parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), parameter logic GBX_IF_EN = 1'b0, + parameter logic USXGMII_EN = 1'b0, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64, @@ -50,6 +51,15 @@ module taxi_eth_mac_phy_10g_rx # output wire logic serdes_rx_bitslip, output wire logic serdes_rx_reset_req, + /* + * Ordered sets + */ + output wire logic [23:0] rx_os, + output wire logic rx_os_sig, + output wire logic rx_os_valid, + output wire logic rx_os_match, + output wire logic rx_idle_match, + /* * PTP */ @@ -84,6 +94,9 @@ module taxi_eth_mac_phy_10g_rx # */ input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518-1, input wire logic cfg_rx_enable, + input wire logic cfg_rx_usxgmii_en = 1'b1, + input wire logic cfg_rx_usxgmii_5g = 1'b0, + input wire logic [2:0] cfg_rx_usxgmii_speed = 3'b011, input wire logic cfg_rx_prbs31_enable ); @@ -144,6 +157,9 @@ eth_phy_10g_rx_if_inst ( if (DATA_W == 64) begin + if (USXGMII_EN) + $fatal(0, "Error: USXGMII is not currently supported in 64-bit mode (instance %m)"); + taxi_axis_baser_rx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), @@ -172,11 +188,11 @@ if (DATA_W == 64) begin /* * Ordered sets */ - .rx_os(), - .rx_os_sig(), - .rx_os_valid(), - .rx_os_match(), - .rx_idle_match(), + .rx_os(rx_os), + .rx_os_sig(rx_os_sig), + .rx_os_valid(rx_os_valid), + .rx_os_match(rx_os_match), + .rx_idle_match(rx_idle_match), /* * PTP @@ -216,6 +232,7 @@ end else begin .DATA_W(DATA_W), .HDR_W(HDR_W), .GBX_IF_EN(GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_W(PTP_TS_W) ) @@ -239,11 +256,11 @@ end else begin /* * Ordered sets */ - .rx_os(), - .rx_os_sig(), - .rx_os_valid(), - .rx_os_match(), - .rx_idle_match(), + .rx_os(rx_os), + .rx_os_sig(rx_os_sig), + .rx_os_valid(rx_os_valid), + .rx_os_match(rx_os_match), + .rx_idle_match(rx_idle_match), /* * PTP @@ -255,6 +272,9 @@ end else begin */ .cfg_rx_max_pkt_len(cfg_rx_max_pkt_len), .cfg_rx_enable(cfg_rx_enable), + .cfg_rx_usxgmii_en(cfg_rx_usxgmii_en), + .cfg_rx_usxgmii_5g(cfg_rx_usxgmii_5g), + .cfg_rx_usxgmii_speed(cfg_rx_usxgmii_speed), /* * Status diff --git a/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv b/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv index 9f39052..f736606 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_10g_tx.sv @@ -20,6 +20,7 @@ module taxi_eth_mac_phy_10g_tx # parameter DATA_W = 64, parameter HDR_W = (DATA_W/32), parameter logic GBX_IF_EN = 1'b0, + parameter logic USXGMII_EN = 1'b0, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, @@ -51,6 +52,14 @@ module taxi_eth_mac_phy_10g_tx # input wire logic serdes_tx_gbx_req_stall = 1'b0, output wire logic serdes_tx_gbx_sync, + /* + * Ordered sets + */ + input wire logic [23:0] tx_os = '0, + input wire logic tx_os_sig = 1'b0, + input wire logic tx_os_valid = 1'b0, + output wire logic tx_os_ready, + /* * PTP */ @@ -81,6 +90,9 @@ module taxi_eth_mac_phy_10g_tx # input wire logic [15:0] cfg_tx_max_pkt_len = 16'd1518-1, input wire logic [7:0] cfg_tx_ifg = 8'd12, input wire logic cfg_tx_enable, + input wire logic cfg_tx_usxgmii_en = 1'b1, + input wire logic cfg_tx_usxgmii_5g = 1'b0, + input wire logic [2:0] cfg_tx_usxgmii_speed = 3'b011, input wire logic cfg_tx_prbs31_enable ); @@ -135,6 +147,9 @@ tx_pad_inst ( if (DATA_W == 64) begin + if (USXGMII_EN) + $fatal(0, "Error: USXGMII is not currently supported in 64-bit mode (instance %m)"); + taxi_axis_baser_tx_64 #( .DATA_W(DATA_W), .HDR_W(HDR_W), @@ -170,10 +185,10 @@ if (DATA_W == 64) begin /* * Ordered sets */ - .tx_os('0), - .tx_os_sig(1'b0), - .tx_os_valid(1'b0), - .tx_os_ready(), + .tx_os(tx_os), + .tx_os_sig(tx_os_sig), + .tx_os_valid(tx_os_valid), + .tx_os_ready(tx_os_ready), /* * PTP @@ -211,6 +226,7 @@ end else begin .HDR_W(HDR_W), .GBX_IF_EN(GBX_IF_EN), .GBX_CNT(1), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_W(PTP_TS_W), @@ -240,10 +256,10 @@ end else begin /* * Ordered sets */ - .tx_os('0), - .tx_os_sig(1'b0), - .tx_os_valid(1'b0), - .tx_os_ready(), + .tx_os(tx_os), + .tx_os_sig(tx_os_sig), + .tx_os_valid(tx_os_valid), + .tx_os_ready(tx_os_ready), /* * PTP @@ -256,6 +272,9 @@ end else begin .cfg_tx_max_pkt_len(cfg_tx_max_pkt_len), .cfg_tx_ifg(cfg_tx_ifg), .cfg_tx_enable(cfg_tx_enable), + .cfg_tx_usxgmii_en(cfg_tx_usxgmii_en), + .cfg_tx_usxgmii_5g(cfg_tx_usxgmii_5g), + .cfg_tx_usxgmii_speed(cfg_tx_usxgmii_speed), /* * Status diff --git a/src/eth/rtl/taxi_eth_phy_10g_usxgmii_an.sv b/src/eth/rtl/taxi_eth_phy_10g_usxgmii_an.sv new file mode 100644 index 0000000..599d4ed --- /dev/null +++ b/src/eth/rtl/taxi_eth_phy_10g_usxgmii_an.sv @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2026 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * USXGMII autonegotiation + */ +module taxi_eth_phy_10g_usxgmii_an # +( + parameter DATA_W = 32 +) +( + input wire logic clk, + input wire logic rst, + + /* + * Ordered sets + */ + input wire logic [23:0] rx_os, + input wire logic rx_os_sig, + input wire logic rx_os_valid, + input wire logic rx_os_match, + input wire logic rx_idle_match, + input wire logic rx_block_lock, + + output wire logic [23:0] tx_os, + output wire logic tx_os_sig, + output wire logic tx_os_valid, + input wire logic tx_os_ready, + + /* + * USXGMII Autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + input wire logic an_timeout_en = 1'b1, + input wire logic an_usxgmii_en = 1'b0, + input wire logic an_usxgmii_auto = 1'b1, + input wire logic an_usxgmii_5g = 1'b0, + output wire logic an_intr, + output wire logic an_running, + output wire logic an_complete, + output wire logic an_timeout, + output wire logic an_usxgmii_mode, + input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601, + output wire logic [15:0] an_lp_adv_ability, + output wire logic an_lp_usxgmii_link, + output wire logic [2:0] an_lp_usxgmii_speed, + output wire logic an_res_full_duplex +); + +localparam logic [15:0] AN_ACK = 16'h4000; +localparam logic [15:0] AN_NP = 16'h8000; + +typedef enum logic [2:0] { + STATE_START, + STATE_AN_RESTART, + STATE_ABILITY_DET, + STATE_ACK_DET, + STATE_ACK_CPL, + STATE_IDLE_DET, + STATE_DONE +} state_t; + +state_t state_reg = STATE_START, state_next; + +// 1 pulse per 100 us for timers +localparam CYC_PER_US = DATA_W == 64 ? 156 : 312; +localparam PRESC_CYC = $rtoi(CYC_PER_US*100); + +logic [16:0] presc_cnt_reg = '0; +logic presc_pulse_reg = 1'b0; +logic [4:0] delay_cnt_reg = '0, delay_cnt_next; +logic delay_run_reg = 1'b0, delay_run_next; +logic [9:0] timeout_cnt_reg = '0, timeout_cnt_next; +logic timeout_run_reg = 1'b0, timeout_run_next; + +logic [23:0] tx_os_reg = '0, tx_os_next; +logic tx_os_valid_reg = 1'b0, tx_os_valid_next; + +logic an_intr_reg = 1'b0, an_intr_next; +logic an_running_reg = 1'b0, an_running_next; +logic an_complete_reg = 1'b0, an_complete_next; +logic an_timeout_reg = 1'b0, an_timeout_next; +logic an_usxgmii_mode_reg = 1'b0, an_usxgmii_mode_next; +logic [15:0] an_lp_adv_ability_reg = '0, an_lp_adv_ability_next; + +assign tx_os = tx_os_reg; +assign tx_os_sig = 1'b0; +assign tx_os_valid = tx_os_valid_reg; + +assign an_intr = an_intr_reg; +assign an_running = an_running_reg; +assign an_complete = an_complete_reg; +assign an_timeout = an_timeout_reg; +assign an_usxgmii_mode = an_usxgmii_mode_reg; +assign an_lp_adv_ability = an_lp_adv_ability_reg; + +// extract config information from link partner ability value +assign an_lp_usxgmii_link = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[15] : 1'b1; +assign an_lp_usxgmii_speed = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[11:9] : 3'b011; +assign an_res_full_duplex = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[12] : 1'b1; + +// TODO: check for stabilized RX config reg values + +always_comb begin + state_next = STATE_START; + + delay_cnt_next = delay_cnt_reg; + delay_run_next = delay_run_reg; + timeout_cnt_next = timeout_cnt_reg; + timeout_run_next = timeout_run_reg; + + tx_os_next = tx_os_reg; + tx_os_valid_next = tx_os_valid_reg && !tx_os_ready; + + an_intr_next = 1'b0; + an_running_next = an_running_reg; + an_complete_next = an_complete_reg; + an_timeout_next = an_timeout_reg; + an_usxgmii_mode_next = an_usxgmii_mode_reg; + an_lp_adv_ability_next = an_lp_adv_ability_reg; + + if (delay_run_reg) begin + if (presc_pulse_reg) begin + if (delay_cnt_reg != 0) begin + delay_cnt_next = delay_cnt_reg - 1; + end else begin + delay_run_next = 1'b0; + end + end + end else begin + // USXGMII: 1.6 ms timer + delay_cnt_next = 16; + end + + if (timeout_run_reg) begin + if (presc_pulse_reg) begin + if (timeout_cnt_reg != 0) begin + timeout_cnt_next = timeout_cnt_reg - 1; + end else begin + timeout_run_next = 1'b0; + end + end + end else begin + // 100 ms timer + timeout_cnt_next = 1000; + end + + case (state_reg) + STATE_START: begin + // start + an_running_next = 1'b0; + an_complete_next = 1'b0; + an_timeout_next = 1'b0; + timeout_run_next = 1'b0; + + if (an_usxgmii_en) begin + an_usxgmii_mode_next = 1'b1; + end else if (!an_usxgmii_auto) begin + an_usxgmii_mode_next = 1'b0; + end + + tx_os_next = {16'd0, 8'h03}; + + if (an_en) begin + if (!an_usxgmii_mode_next) begin + state_next = STATE_DONE; + end else begin + tx_os_valid_next = 1'b1; + if (delay_run_reg) begin + // restart link timer + delay_run_next = 1'b0; + state_next = STATE_START; + end else begin + // AN restart state + delay_run_next = 1'b1; + an_running_next = 1'b1; + state_next = STATE_AN_RESTART; + end + end + end else begin + // AN disabled + an_usxgmii_mode_next = 1'b0; + state_next = STATE_START; + end + end + STATE_AN_RESTART: begin + // AN restart - send zeroed config reg to trigger link partner to restart the AN process + tx_os_next = {16'd0, 8'h03}; + tx_os_valid_next = 1'b1; + + if (!delay_run_reg) begin + // link timer expired + timeout_run_next = 1'b1; + state_next = STATE_ABILITY_DET; + end else begin + state_next = STATE_AN_RESTART; + end + end + STATE_ABILITY_DET: begin + // ability detect state - transfer AN ability value with ACK clear + tx_os_next[23:8] = an_adv_ability_usxgmii & ~AN_ACK; + tx_os_valid_next = 1'b1; + + if (rx_os_match && rx_os[23:8] != 0 && rx_os[7:0] == 8'h03) begin + // got USXGMII ability advertisement from link partner + an_lp_adv_ability_next = rx_os[23:8]; + state_next = STATE_ACK_DET; + end else if (!timeout_run_reg && an_timeout_en) begin + // timed out, no AN response from link partner + an_timeout_next = 1'b1; + if (!an_usxgmii_en) begin + an_usxgmii_mode_next = 1'b0; + end + state_next = STATE_DONE; + end else begin + state_next = STATE_ABILITY_DET; + end + end + STATE_ACK_DET: begin + // acknowledge detect - wait for ACK from link partner + tx_os_next[23:8] = tx_os_reg[23:8] | AN_ACK; + tx_os_valid_next = 1'b1; + + if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin + // restart request from link partner + state_next = STATE_START; + end else if (rx_os_match && rx_os[14+8] && rx_os[7:0] == 8'h03) begin + // acknowledge match + an_lp_adv_ability_next = rx_os[23:8]; + if (rx_os[23:8] == (an_lp_adv_ability_reg | AN_ACK)) begin + // consistent with previously-seen value + delay_run_next = 1'b1; + state_next = STATE_ACK_CPL; + end else begin + // inconsistent, restart AN + state_next = STATE_START; + end + end else begin + state_next = STATE_ACK_DET; + end + end + STATE_ACK_CPL: begin + // complete acknowledge - give link partner time to detect our ACK + tx_os_next[23:8] = tx_os_reg[23:8] | AN_ACK; + tx_os_valid_next = 1'b1; + + if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin + // restart request from link partner + state_next = STATE_START; + end else if (!delay_run_reg) begin + // link timer expired + if (an_lp_adv_ability_reg[0] == 1'b1 && rx_os[7:0] == 8'h03) begin + // mode matches + delay_run_next = 1'b1; + state_next = STATE_IDLE_DET; + end else begin + // mode mismatch + if (an_usxgmii_en) begin + state_next = STATE_START; + end else begin + an_usxgmii_mode_next = 1'b0; + state_next = STATE_DONE; + end + end + end else begin + state_next = STATE_ACK_CPL; + end + end + STATE_IDLE_DET: begin + // idle detect - wait for link to go idle + if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin + // restart request from link partner + state_next = STATE_START; + end else if (rx_idle_match && !delay_run_reg) begin + // idle match and link timer expired + an_complete_next = 1'b1; + state_next = STATE_DONE; + end else begin + state_next = STATE_IDLE_DET; + end + end + STATE_DONE: begin + // AN operation complete + an_running_next = 1'b0; + timeout_run_next = 1'b0; + + if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin + // restart request from link partner + an_usxgmii_mode_next = 1'b1; + state_next = STATE_START; + end else begin + state_next = STATE_DONE; + end + end + default: begin + state_next = STATE_START; + end + endcase + + if (!an_en || an_restart || !rx_block_lock) begin + an_usxgmii_mode_next = an_en && an_usxgmii_en; + if (an_usxgmii_en) begin + an_usxgmii_mode_next = 1'b1; + end else if (!an_usxgmii_auto) begin + an_usxgmii_mode_next = 1'b0; + end else if (an_usxgmii_auto && rx_os_match && rx_os[7:0] == 8'h03) begin + an_usxgmii_mode_next = 1'b1; + end + state_next = STATE_START; + end +end + +always @(posedge clk) begin + state_reg <= state_next; + + delay_cnt_reg <= delay_cnt_next; + delay_run_reg <= delay_run_next; + timeout_cnt_reg <= timeout_cnt_next; + timeout_run_reg <= timeout_run_next; + + tx_os_reg <= tx_os_next; + tx_os_valid_reg <= tx_os_valid_next; + + an_intr_reg <= an_intr_next; + an_running_reg <= an_running_next; + an_complete_reg <= an_complete_next; + an_timeout_reg <= an_timeout_next; + an_usxgmii_mode_reg <= an_usxgmii_mode_next; + an_lp_adv_ability_reg <= an_lp_adv_ability_next; + + presc_pulse_reg <= 1'b0; + if (presc_cnt_reg != 0) begin + presc_cnt_reg <= presc_cnt_reg - 1; + end else begin + presc_pulse_reg <= 1'b1; + presc_cnt_reg <= 17'(an_speedup ? PRESC_CYC / 1000 : PRESC_CYC); + end + + if (rst) begin + state_reg <= STATE_START; + + presc_cnt_reg <= '0; + presc_pulse_reg <= 1'b0; + delay_cnt_reg <= '0; + delay_run_reg <= 1'b0; + timeout_cnt_reg <= '0; + timeout_run_reg <= 1'b0; + + tx_os_valid_reg <= 1'b0; + + an_intr_reg <= 1'b0; + an_running_reg <= 1'b0; + an_complete_reg <= 1'b0; + an_timeout_reg <= 1'b0; + an_usxgmii_mode_reg <= 1'b0; + end +end + +endmodule + +`resetall diff --git a/src/eth/rtl/us/taxi_eth_mac_25g_us.sv b/src/eth/rtl/us/taxi_eth_mac_25g_us.sv index db1469c..b67d5bc 100644 --- a/src/eth/rtl/us/taxi_eth_mac_25g_us.sv +++ b/src/eth/rtl/us/taxi_eth_mac_25g_us.sv @@ -54,6 +54,7 @@ module taxi_eth_mac_25g_us # // MAC/PHY parameters parameter logic COMBINED_MAC_PCS = 1'b1, parameter DATA_W = 64, + parameter logic USXGMII_EN = 1'b0, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -133,6 +134,26 @@ module taxi_eth_mac_25g_us # */ taxi_axis_if.src m_axis_rx[CNT], + /* + * USXGMII autonegotiation + */ + input wire logic an_en[CNT] = '{CNT{1'b1}}, + input wire logic an_restart[CNT] = '{CNT{1'b0}}, + input wire logic an_speedup[CNT] = '{CNT{1'b0}}, + input wire logic an_timeout_en[CNT] = '{CNT{1'b1}}, + input wire logic an_usxgmii_en[CNT] = '{CNT{1'b0}}, + input wire logic an_usxgmii_auto[CNT] = '{CNT{1'b1}}, + output wire logic an_intr[CNT], + output wire logic an_running[CNT], + output wire logic an_complete[CNT], + output wire logic an_timeout[CNT], + output wire logic an_usxgmii_mode[CNT], + input wire logic [15:0] an_adv_ability_usxgmii[CNT] = '{CNT{16'h1601}}, + output wire logic [15:0] an_lp_adv_ability[CNT], + output wire logic an_lp_usxgmii_link[CNT], + output wire logic [2:0] an_lp_usxgmii_speed[CNT], + output wire logic an_res_full_duplex[CNT], + /* * PTP clock */ @@ -426,6 +447,7 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch // MAC/PHY parameters .COMBINED_MAC_PCS(COMBINED_MAC_PCS), .DATA_W(DATA_W), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -519,6 +541,26 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch */ .m_axis_rx(m_axis_rx[n]), + /* + * USXGMII autonegotiation + */ + .an_en(an_en[n]), + .an_restart(an_restart[n]), + .an_speedup(an_speedup[n]), + .an_timeout_en(an_timeout_en[n]), + .an_usxgmii_en(an_usxgmii_en[n]), + .an_usxgmii_auto(an_usxgmii_auto[n]), + .an_intr(an_intr[n]), + .an_running(an_running[n]), + .an_complete(an_complete[n]), + .an_timeout(an_timeout[n]), + .an_usxgmii_mode(an_usxgmii_mode[n]), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii[n]), + .an_lp_adv_ability(an_lp_adv_ability[n]), + .an_lp_usxgmii_link(an_lp_usxgmii_link[n]), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed[n]), + .an_res_full_duplex(an_res_full_duplex[n]), + /* * PTP clock */ diff --git a/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv b/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv index aa6eca7..5b40e24 100644 --- a/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv +++ b/src/eth/rtl/us/taxi_eth_mac_25g_us_ch.sv @@ -53,6 +53,7 @@ module taxi_eth_mac_25g_us_ch # // MAC/PHY parameters parameter logic COMBINED_MAC_PCS = 1'b1, parameter DATA_W = 64, + parameter logic USXGMII_EN = 1'b0, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -146,6 +147,26 @@ module taxi_eth_mac_25g_us_ch # */ taxi_axis_if.src m_axis_rx, + /* + * USXGMII autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + input wire logic an_timeout_en = 1'b1, + input wire logic an_usxgmii_en = 1'b0, + input wire logic an_usxgmii_auto = 1'b1, + output wire logic an_intr, + output wire logic an_running, + output wire logic an_complete, + output wire logic an_timeout, + output wire logic an_usxgmii_mode, + input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601, + output wire logic [15:0] an_lp_adv_ability, + output wire logic an_lp_usxgmii_link, + output wire logic [2:0] an_lp_usxgmii_speed, + output wire logic an_res_full_duplex, + /* * PTP clock */ @@ -885,6 +906,7 @@ if (COMBINED_MAC_PCS) begin : mac .HDR_W(HDR_W), .TX_GBX_IF_EN(GBX_EN), .RX_GBX_IF_EN(GBX_EN), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -943,6 +965,27 @@ if (COMBINED_MAC_PCS) begin : mac .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(rx_reset_req), + /* + * USXGMII autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_usxgmii_5g(1'b0), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex), + /* * PTP */ diff --git a/src/eth/tb/taxi_eth_mac_25g_us/Makefile b/src/eth/tb/taxi_eth_mac_25g_us/Makefile index cbcf6bb..e31cda2 100644 --- a/src/eth/tb/taxi_eth_mac_25g_us/Makefile +++ b/src/eth/tb/taxi_eth_mac_25g_us/Makefile @@ -44,6 +44,7 @@ export PARAM_QPLL0_EXT_CTRL := 0 export PARAM_QPLL1_EXT_CTRL := 0 export PARAM_COMBINED_MAC_PCS := 1 export PARAM_DATA_W := 64 +export PARAM_USXGMII_EN := 0 export PARAM_DIC_EN := 1 export PARAM_PTP_TS_EN := 1 export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN) diff --git a/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.py b/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.py index f956449..9c17bc9 100644 --- a/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.py +++ b/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.py @@ -22,7 +22,7 @@ import cocotb_test.simulator import cocotb from cocotb.clock import Clock -from cocotb.triggers import RisingEdge +from cocotb.triggers import RisingEdge, Timer from cocotb.utils import get_time_from_sim_steps from cocotb.regression import TestFactory @@ -138,6 +138,14 @@ class TB: dut.rx_rst_in.setimmediatevalue([0]*4) dut.tx_rst_in.setimmediatevalue([0]*4) + dut.an_en.setimmediatevalue([0]*4) + dut.an_restart.setimmediatevalue([0]*4) + dut.an_speedup.setimmediatevalue([1]*4) + dut.an_timeout_en.setimmediatevalue([1]*4) + dut.an_usxgmii_en.setimmediatevalue([0]*4) + dut.an_usxgmii_auto.setimmediatevalue([1]*4) + dut.an_adv_ability_usxgmii.setimmediatevalue([0x1601]*4) + dut.stat_rx_fifo_drop.setimmediatevalue([0]*4) dut.cfg_tx_pad_en.setimmediatevalue([0]*4) @@ -956,6 +964,159 @@ async def run_test_pfc(dut, port=0, ifg=12): await RisingEdge(dut.xcvr_ctrl_clk) +async def run_usxgmii_an(tb, port=0, cfg=0x0001): + # link timer scaled by 1000x for faster simulation + link_timer = Timer(1.6, 'us') + + dut = tb.dut + + for k in range(10): + tb.log.info("AN_RESTART") + tb.serdes_sources[port].set_seq_os((0x0000 << 8) | 0x03) + + await link_timer + + tb.log.info("ABILITY_DETECT") + tb.serdes_sources[port].set_seq_os(((cfg & ~0x4000) << 8) | 0x03) + tb.serdes_sinks[port].get_os() + + lp_cfg = None + while True: + await RisingEdge(dut.tx_clk[port]) + lp_cfg = tb.serdes_sinks[port].get_os()[0] + if lp_cfg is None: + continue + if lp_cfg & 0xff != 0x03: + continue + lp_cfg = lp_cfg >> 8 + if tb.serdes_sinks[port].get_os_match() and lp_cfg != 0: + break + + tb.log.info("ACKNOWLEDGE_DETECT") + tb.serdes_sources[port].set_seq_os(((cfg | 0x4000) << 8) | 0x03) + tb.serdes_sinks[port].get_os() + + lp_cfg_ack = None + while True: + await RisingEdge(dut.tx_clk[port]) + lp_cfg_ack = tb.serdes_sinks[port].get_os()[0] + if lp_cfg_ack is None: + continue + if lp_cfg_ack & 0xff != 0x03: + continue + lp_cfg_ack = lp_cfg_ack >> 8 + if tb.serdes_sinks[port].get_os_match() and lp_cfg_ack & 0x4000: + break + elif tb.serdes_sinks[port].get_os_match() and lp_cfg_ack == 0: + break + + if lp_cfg | 0x4000 != lp_cfg_ack: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack) + continue + + if lp_cfg_ack == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("COMPLETE_ACKNOWLEDGE") + await link_timer + + tb.log.info("IDLE_DETECT") + tb.serdes_sources[port].set_seq_os(None) + + await link_timer + + lp_cfg_ack2 = None + while True: + await RisingEdge(dut.tx_clk[port]) + if tb.serdes_sinks[port].get_idle_match(): + break + lp_cfg_ack2 = tb.serdes_sinks[port].get_os()[0] + if lp_cfg_ack2 is None: + continue + if lp_cfg_ack2 & 0xff != 0x03: + continue + lp_cfg_ack2 = lp_cfg_ack2 >> 8 + if tb.serdes_sinks[port].get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2): + break + + if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2) + continue + + if lp_cfg_ack2 == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("AN done") + return lp_cfg_ack + + tb.log.warning("AN timed out") + tb.serdes_sources[port].set_seq_os(None) + return None + + +async def run_test_usxgmii(dut, port=0): + + tb = TB(dut) + + dut.an_en[port].value = 1 + dut.an_restart[port].value = 0 + dut.an_speedup[port].value = 1 + dut.an_timeout_en[port].value = 1 + dut.an_usxgmii_en[port].value = 0 + dut.an_usxgmii_auto[port].value = 1 + dut.an_adv_ability_usxgmii[port].value = 0x1601 + + await tb.reset() + + tb.log.info("Wait for reset") + while int(dut.rx_rst_out[port].value): + await RisingEdge(dut.xcvr_ctrl_clk) + + tb.log.info("Wait for block lock") + while not int(dut.rx_block_lock[port].value): + await RisingEdge(dut.xcvr_ctrl_clk) + + for k in range(100): + await RisingEdge(dut.xcvr_ctrl_clk) + + if 1: + for x in range(6): + cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14) + cfg2 = cfg1 + dut.an_adv_ability_usxgmii[port].value = cfg2 + + lp_cfg = await run_usxgmii_an(tb, port, cfg1) + + for k in range(2000): + if not dut.an_running[port].value: + break + await RisingEdge(dut.tx_clk[port]) + + assert lp_cfg == cfg2 | 0x4000 + assert not int(dut.an_running[port].value) + assert int(dut.an_complete[port].value) + assert not int(dut.an_timeout[port].value) + assert int(dut.an_usxgmii_mode[port].value) + assert int(dut.an_lp_adv_ability[port].value) == cfg1 | 0x4000 + assert bool(dut.an_lp_usxgmii_link[port].value) == bool((cfg1 >> 15) & 1) + assert int(dut.an_lp_usxgmii_speed[port].value) == (cfg1 >> 9) & 0x7 + assert bool(dut.an_res_full_duplex[port].value) == bool((cfg1 >> 12) & 1) + else: + lp_cfg = await run_usxgmii_an(tb, port, 0x9801) + + for k in range(2000): + if not dut.an_running[port].value: + break + await RisingEdge(dut.tx_clk[port]) + + assert lp_cfg is None + + for k in range(10): + await RisingEdge(dut.tx_clk[port]) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -1002,6 +1163,11 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("ifg", [12]) factory.generate_tests() + if cocotb.top.USXGMII_EN.value: + for test in [run_test_usxgmii]: + factory = TestFactory(test) + factory.generate_tests() + # cocotb-test @@ -1054,6 +1220,7 @@ def test_taxi_eth_mac_25g_us(request, data_w, combined_mac_pcs, low_latency, dic parameters['QPLL1_EXT_CTRL'] = 0 parameters['COMBINED_MAC_PCS'] = combined_mac_pcs parameters['DATA_W'] = data_w + parameters['USXGMII_EN'] = int(data_w == 32) parameters['DIC_EN'] = dic_en parameters['PTP_TS_EN'] = 1 parameters['PTP_TD_EN'] = parameters['PTP_TS_EN'] diff --git a/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.sv b/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.sv index d9b7ffd..f75d933 100644 --- a/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.sv +++ b/src/eth/tb/taxi_eth_mac_25g_us/test_taxi_eth_mac_25g_us.sv @@ -43,6 +43,7 @@ module test_taxi_eth_mac_25g_us # parameter logic [CNT-1:0] GT_RX_POLARITY = '0, parameter logic COMBINED_MAC_PCS = 1'b1, parameter DATA_W = 64, + parameter logic USXGMII_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -113,6 +114,23 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_ taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl[CNT](); taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx[CNT](); +logic an_en[CNT]; +logic an_restart[CNT]; +logic an_speedup[CNT]; +logic an_timeout_en[CNT]; +logic an_usxgmii_en[CNT]; +logic an_usxgmii_auto[CNT]; +logic an_intr[CNT]; +logic an_running[CNT]; +logic an_complete[CNT]; +logic an_timeout[CNT]; +logic an_usxgmii_mode[CNT]; +logic [15:0] an_adv_ability_usxgmii[CNT]; +logic [15:0] an_lp_adv_ability[CNT]; +logic an_lp_usxgmii_link[CNT]; +logic [2:0] an_lp_usxgmii_speed[CNT]; +logic an_res_full_duplex[CNT]; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -266,6 +284,7 @@ taxi_eth_mac_25g_us #( .GT_RX_POLARITY(GT_RX_POLARITY), .COMBINED_MAC_PCS(COMBINED_MAC_PCS), .DATA_W(DATA_W), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -345,6 +364,26 @@ uut ( */ .m_axis_rx(m_axis_rx), + /* + * USXGMII autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex), + /* * PTP */ diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/Makefile b/src/eth/tb/taxi_eth_mac_phy_10g/Makefile index d1303d6..7b0dfb0 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_10g/Makefile @@ -36,6 +36,7 @@ export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 export PARAM_TX_GBX_IF_EN := 1 export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN) +export PARAM_USXGMII_EN := 0 export PARAM_DIC_EN := 1 export PARAM_PTP_TS_EN := 1 export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN) diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py index 5f82cda..3dac3a4 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py +++ b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.py @@ -22,7 +22,7 @@ import cocotb_test.simulator import cocotb from cocotb.clock import Clock -from cocotb.triggers import RisingEdge +from cocotb.triggers import RisingEdge, Timer from cocotb.utils import get_time_from_sim_steps from cocotb.regression import TestFactory @@ -106,6 +106,15 @@ class TB: period_ns=self.ptp_clk_period ) + dut.an_en.setimmediatevalue(0) + dut.an_restart.setimmediatevalue(0) + dut.an_speedup.setimmediatevalue(1) + dut.an_timeout_en.setimmediatevalue(1) + dut.an_usxgmii_en.setimmediatevalue(0) + dut.an_usxgmii_auto.setimmediatevalue(1) + dut.an_usxgmii_5g.setimmediatevalue(0) + dut.an_adv_ability_usxgmii.setimmediatevalue(0x1601) + dut.stat_rx_fifo_drop.setimmediatevalue(0) dut.cfg_tx_pad_en.setimmediatevalue(0) @@ -850,6 +859,152 @@ async def run_test_pfc(dut, gbx_cfg=None, ifg=12): await RisingEdge(dut.tx_clk) +async def run_usxgmii_an(tb, cfg): + # link timer scaled by 1000x for faster simulation + link_timer = Timer(1.6, 'us') + + dut = tb.dut + + for k in range(10): + tb.log.info("AN_RESTART") + tb.serdes_source.set_seq_os((0x0000 << 8) | 0x03) + + await link_timer + + tb.log.info("ABILITY_DETECT") + tb.serdes_source.set_seq_os(((cfg & ~0x4000) << 8) | 0x03) + tb.serdes_sink.get_os() + + lp_cfg = None + while True: + await RisingEdge(dut.tx_clk) + lp_cfg = tb.serdes_sink.get_os()[0] + if lp_cfg is None: + continue + if lp_cfg & 0xff != 0x03: + continue + lp_cfg = lp_cfg >> 8 + if tb.serdes_sink.get_os_match() and lp_cfg != 0: + break + + tb.log.info("ACKNOWLEDGE_DETECT") + tb.serdes_source.set_seq_os(((cfg | 0x4000) << 8) | 0x03) + tb.serdes_sink.get_os() + + lp_cfg_ack = None + while True: + await RisingEdge(dut.tx_clk) + lp_cfg_ack = tb.serdes_sink.get_os()[0] + if lp_cfg_ack is None: + continue + if lp_cfg_ack & 0xff != 0x03: + continue + lp_cfg_ack = lp_cfg_ack >> 8 + if tb.serdes_sink.get_os_match() and lp_cfg_ack & 0x4000: + break + elif tb.serdes_sink.get_os_match() and lp_cfg_ack == 0: + break + + if lp_cfg | 0x4000 != lp_cfg_ack: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack) + continue + + if lp_cfg_ack == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("COMPLETE_ACKNOWLEDGE") + await link_timer + + tb.log.info("IDLE_DETECT") + tb.serdes_source.set_seq_os(None) + + await link_timer + + lp_cfg_ack2 = None + while True: + await RisingEdge(dut.tx_clk) + if tb.serdes_sink.get_idle_match(): + break + lp_cfg_ack2 = tb.serdes_sink.get_os()[0] + if lp_cfg_ack2 is None: + continue + if lp_cfg_ack2 & 0xff != 0x03: + continue + lp_cfg_ack2 = lp_cfg_ack2 >> 8 + if tb.serdes_sink.get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2): + break + + if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2) + continue + + if lp_cfg_ack2 == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("AN done") + return lp_cfg_ack + + tb.log.warning("AN timed out") + tb.serdes_source.set_seq_os(None) + return None + + +async def run_test_usxgmii(dut, gbx_cfg=None): + + tb = TB(dut, gbx_cfg) + + dut.an_en.value = 1 + dut.an_restart.value = 0 + dut.an_speedup.value = 1 + dut.an_timeout_en.value = 1 + dut.an_usxgmii_en.value = 0 + dut.an_usxgmii_auto.value = 1 + dut.an_usxgmii_5g.value = 0 + dut.an_adv_ability_usxgmii.value = 0x1601 + + await tb.reset() + + for k in range(100): + await RisingEdge(dut.tx_clk) + + if 1: + for x in range(6): + cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14) + cfg2 = cfg1 + dut.an_adv_ability_usxgmii.value = cfg2 + + lp_cfg = await run_usxgmii_an(tb, cfg1) + + for k in range(2000): + if not dut.an_running.value: + break + await RisingEdge(dut.tx_clk) + + assert lp_cfg == cfg2 | 0x4000 + assert not int(dut.an_running.value) + assert int(dut.an_complete.value) + assert not int(dut.an_timeout.value) + assert int(dut.an_usxgmii_mode.value) + assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000 + assert bool(dut.an_lp_usxgmii_link.value) == bool((cfg1 >> 15) & 1) + assert int(dut.an_lp_usxgmii_speed.value) == (cfg1 >> 9) & 0x7 + assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1) + else: + lp_cfg = await run_usxgmii_an(tb, 0x9801) + + for k in range(2000): + if not dut.an_running.value: + break + await RisingEdge(dut.tx_clk) + + assert lp_cfg is None + + for k in range(10): + await RisingEdge(dut.tx_clk) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -904,6 +1059,12 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() + if cocotb.top.USXGMII_EN.value: + for test in [run_test_usxgmii]: + factory = TestFactory(test) + factory.add_option("gbx_cfg", gbx_cfgs) + factory.generate_tests() + # cocotb-test @@ -948,6 +1109,7 @@ def test_taxi_eth_mac_phy_10g(request, data_w, ptp_td_en, gbx_en, dic_en, pfc_en parameters['HDR_W'] = 2 parameters['TX_GBX_IF_EN'] = gbx_en parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN'] + parameters['USXGMII_EN'] = int(data_w == 32) parameters['DIC_EN'] = dic_en parameters['PTP_TS_EN'] = 1 parameters['PTP_TD_EN'] = ptp_td_en diff --git a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv index 21a448b..2dfe9d1 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv +++ b/src/eth/tb/taxi_eth_mac_phy_10g/test_taxi_eth_mac_phy_10g.sv @@ -22,6 +22,7 @@ module test_taxi_eth_mac_phy_10g # parameter HDR_W = 2, parameter logic TX_GBX_IF_EN = 1'b0, parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, + parameter logic USXGMII_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -76,6 +77,24 @@ logic serdes_rx_hdr_valid; logic serdes_rx_bitslip; logic serdes_rx_reset_req; +logic an_en; +logic an_restart; +logic an_speedup; +logic an_timeout_en; +logic an_usxgmii_en; +logic an_usxgmii_auto; +logic an_usxgmii_5g; +logic an_intr; +logic an_running; +logic an_complete; +logic an_timeout; +logic an_usxgmii_mode; +logic [15:0] an_adv_ability_usxgmii; +logic [15:0] an_lp_adv_ability; +logic an_lp_usxgmii_link; +logic [2:0] an_lp_usxgmii_speed; +logic an_res_full_duplex; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -208,6 +227,7 @@ taxi_eth_mac_phy_10g #( .HDR_W(HDR_W), .TX_GBX_IF_EN(TX_GBX_IF_EN), .RX_GBX_IF_EN(RX_GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -266,6 +286,27 @@ uut ( .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * USXGMII autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_usxgmii_5g(an_usxgmii_5g), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex), + /* * PTP */ diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile index b3a5216..45f75bd 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/Makefile @@ -36,6 +36,7 @@ export PARAM_DATA_W := 64 export PARAM_HDR_W := 2 export PARAM_TX_GBX_IF_EN := 1 export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN) +export PARAM_USXGMII_EN := 0 export PARAM_AXIS_DATA_W := $(PARAM_DATA_W) export PARAM_DIC_EN := 1 export PARAM_PTP_TS_EN := 1 diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py index d383bd2..9e19b3b 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.py @@ -19,7 +19,7 @@ import cocotb_test.simulator import cocotb from cocotb.clock import Clock -from cocotb.triggers import RisingEdge +from cocotb.triggers import RisingEdge, Timer from cocotb.utils import get_time_from_sim_steps from cocotb.regression import TestFactory @@ -104,6 +104,15 @@ class TB: period_ns=self.ptp_clk_period ) + dut.an_en.setimmediatevalue(0) + dut.an_restart.setimmediatevalue(0) + dut.an_speedup.setimmediatevalue(1) + dut.an_timeout_en.setimmediatevalue(1) + dut.an_usxgmii_en.setimmediatevalue(0) + dut.an_usxgmii_auto.setimmediatevalue(1) + dut.an_usxgmii_5g.setimmediatevalue(0) + dut.an_adv_ability_usxgmii.setimmediatevalue(0x1601) + dut.cfg_tx_pad_en.setimmediatevalue(0) dut.cfg_tx_min_pkt_len.setimmediatevalue(0) dut.cfg_tx_max_pkt_len.setimmediatevalue(0) @@ -405,6 +414,152 @@ async def run_test_rx_frame_sync(dut, gbx_cfg=None): await RisingEdge(dut.rx_clk) +async def run_usxgmii_an(tb, cfg): + # link timer scaled by 1000x for faster simulation + link_timer = Timer(1.6, 'us') + + dut = tb.dut + + for k in range(10): + tb.log.info("AN_RESTART") + tb.serdes_source.set_seq_os((0x0000 << 8) | 0x03) + + await link_timer + + tb.log.info("ABILITY_DETECT") + tb.serdes_source.set_seq_os(((cfg & ~0x4000) << 8) | 0x03) + tb.serdes_sink.get_os() + + lp_cfg = None + while True: + await RisingEdge(dut.tx_clk) + lp_cfg = tb.serdes_sink.get_os()[0] + if lp_cfg is None: + continue + if lp_cfg & 0xff != 0x03: + continue + lp_cfg = lp_cfg >> 8 + if tb.serdes_sink.get_os_match() and lp_cfg != 0: + break + + tb.log.info("ACKNOWLEDGE_DETECT") + tb.serdes_source.set_seq_os(((cfg | 0x4000) << 8) | 0x03) + tb.serdes_sink.get_os() + + lp_cfg_ack = None + while True: + await RisingEdge(dut.tx_clk) + lp_cfg_ack = tb.serdes_sink.get_os()[0] + if lp_cfg_ack is None: + continue + if lp_cfg_ack & 0xff != 0x03: + continue + lp_cfg_ack = lp_cfg_ack >> 8 + if tb.serdes_sink.get_os_match() and lp_cfg_ack & 0x4000: + break + elif tb.serdes_sink.get_os_match() and lp_cfg_ack == 0: + break + + if lp_cfg | 0x4000 != lp_cfg_ack: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack) + continue + + if lp_cfg_ack == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("COMPLETE_ACKNOWLEDGE") + await link_timer + + tb.log.info("IDLE_DETECT") + tb.serdes_source.set_seq_os(None) + + await link_timer + + lp_cfg_ack2 = None + while True: + await RisingEdge(dut.tx_clk) + if tb.serdes_sink.get_idle_match(): + break + lp_cfg_ack2 = tb.serdes_sink.get_os()[0] + if lp_cfg_ack2 is None: + continue + if lp_cfg_ack2 & 0xff != 0x03: + continue + lp_cfg_ack2 = lp_cfg_ack2 >> 8 + if tb.serdes_sink.get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2): + break + + if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2: + tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2) + continue + + if lp_cfg_ack2 == 0: + tb.log.warning("AN restart requested") + continue + + tb.log.info("AN done") + return lp_cfg_ack + + tb.log.warning("AN timed out") + tb.serdes_source.set_seq_os(None) + return None + + +async def run_test_usxgmii(dut, gbx_cfg=None): + + tb = TB(dut, gbx_cfg) + + dut.an_en.value = 1 + dut.an_restart.value = 0 + dut.an_speedup.value = 1 + dut.an_timeout_en.value = 1 + dut.an_usxgmii_en.value = 0 + dut.an_usxgmii_auto.value = 1 + dut.an_usxgmii_5g.value = 0 + dut.an_adv_ability_usxgmii.value = 0x1601 + + await tb.reset() + + for k in range(100): + await RisingEdge(dut.tx_clk) + + if 1: + for x in range(6): + cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14) + cfg2 = cfg1 + dut.an_adv_ability_usxgmii.value = cfg2 + + lp_cfg = await run_usxgmii_an(tb, cfg1) + + for k in range(2000): + if not dut.an_running.value: + break + await RisingEdge(dut.tx_clk) + + assert lp_cfg == cfg2 | 0x4000 + assert not int(dut.an_running.value) + assert int(dut.an_complete.value) + assert not int(dut.an_timeout.value) + assert int(dut.an_usxgmii_mode.value) + assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000 + assert bool(dut.an_lp_usxgmii_link.value) == bool((cfg1 >> 15) & 1) + assert int(dut.an_lp_usxgmii_speed.value) == (cfg1 >> 9) & 0x7 + assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1) + else: + lp_cfg = await run_usxgmii_an(tb, 0x9801) + + for k in range(2000): + if not dut.an_running.value: + break + await RisingEdge(dut.tx_clk) + + assert lp_cfg is None + + for k in range(10): + await RisingEdge(dut.tx_clk) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -445,6 +600,12 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() + if cocotb.top.USXGMII_EN.value: + for test in [run_test_usxgmii]: + factory = TestFactory(test) + factory.add_option("gbx_cfg", gbx_cfgs) + factory.generate_tests() + # cocotb-test @@ -488,6 +649,7 @@ def test_taxi_eth_mac_phy_10g_fifo(request, data_w, gbx_en, dic_en): parameters['HDR_W'] = 2 parameters['TX_GBX_IF_EN'] = gbx_en parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN'] + parameters['USXGMII_EN'] = int(data_w == 32) parameters['AXIS_DATA_W'] = parameters['DATA_W'] parameters['DIC_EN'] = dic_en parameters['PTP_TS_EN'] = 1 diff --git a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv index 67e9bbb..f9909ef 100644 --- a/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv +++ b/src/eth/tb/taxi_eth_mac_phy_10g_fifo/test_taxi_eth_mac_phy_10g_fifo.sv @@ -22,6 +22,7 @@ module test_taxi_eth_mac_phy_10g_fifo # parameter HDR_W = 2, parameter logic TX_GBX_IF_EN = 1'b0, parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN, + parameter logic USXGMII_EN = 1'b1, parameter AXIS_DATA_W = 8, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, @@ -90,6 +91,24 @@ logic serdes_rx_hdr_valid; logic serdes_rx_bitslip; logic serdes_rx_reset_req; +logic an_en; +logic an_restart; +logic an_speedup; +logic an_timeout_en; +logic an_usxgmii_en; +logic an_usxgmii_auto; +logic an_usxgmii_5g; +logic an_intr; +logic an_running; +logic an_complete; +logic an_timeout; +logic an_usxgmii_mode; +logic [15:0] an_adv_ability_usxgmii; +logic [15:0] an_lp_adv_ability; +logic an_lp_usxgmii_link; +logic [2:0] an_lp_usxgmii_speed; +logic an_res_full_duplex; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -137,6 +156,7 @@ taxi_eth_mac_phy_10g_fifo #( .HDR_W(HDR_W), .TX_GBX_IF_EN(TX_GBX_IF_EN), .RX_GBX_IF_EN(RX_GBX_IF_EN), + .USXGMII_EN(USXGMII_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -208,6 +228,27 @@ uut ( .serdes_rx_bitslip(serdes_rx_bitslip), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * USXGMII autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_timeout_en(an_timeout_en), + .an_usxgmii_en(an_usxgmii_en), + .an_usxgmii_auto(an_usxgmii_auto), + .an_usxgmii_5g(an_usxgmii_5g), + .an_intr(an_intr), + .an_running(an_running), + .an_complete(an_complete), + .an_timeout(an_timeout), + .an_usxgmii_mode(an_usxgmii_mode), + .an_adv_ability_usxgmii(an_adv_ability_usxgmii), + .an_lp_adv_ability(an_lp_adv_ability), + .an_lp_usxgmii_link(an_lp_usxgmii_link), + .an_lp_usxgmii_speed(an_lp_usxgmii_speed), + .an_res_full_duplex(an_res_full_duplex), + /* * PTP clock */