1//
2// Copyright 2016-2017 Ettus Research LLC
3// Copyright 2017 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7// sfpp_io_core
8// - mdio_master
9// - One Gige phy + MAC
10// - Ten Gige phy + MAC
11// - Aurora phy + MAC
12//
13//////////////////////////////////////////////////////////////////////
14
15module x300_sfpp_io_core #(
16   parameter PROTOCOL = "10GbE",    // Must be {10GbE, 1GbE, Aurora}
17   parameter PORTNUM  = 8'd0
18)(
19   input             areset,
20   input             bus_rst,
21   input             bus_rst_div2,
22
23   input             gt_refclk,
24   input             gb_refclk,
25   input             misc_clk,
26   input             bus_clk,
27   input             bus_clk_div2,
28
29   output            txp,
30   output            txn,
31   input             rxp,
32   input             rxn,
33
34   input             sfpp_rxlos,
35   input             sfpp_tx_fault,
36   output            sfpp_tx_disable,
37
38   input  [63:0]     s_axis_tdata,
39   input  [3:0]      s_axis_tuser,
40   input             s_axis_tlast,
41   input             s_axis_tvalid,
42   output            s_axis_tready,
43
44   output [63:0]     m_axis_tdata,
45   output [3:0]      m_axis_tuser,
46   output            m_axis_tlast,
47   output            m_axis_tvalid,
48   input             m_axis_tready,
49
50   input  [7:0]      wb_adr_i,
51   input             wb_cyc_i,
52   input  [31:0]     wb_dat_i,
53   input             wb_stb_i,
54   input             wb_we_i,
55   output            wb_ack_o,
56   output [31:0]     wb_dat_o,
57   output            wb_int_o,
58
59   output [15:0]     phy_status,
60   output            link_up,
61   output            activity
62);
63
64   wire mdc, mdio_in, mdio_out;
65
66    // Flush logic: If the link is not up, we will flush all packets coming from
67    // the device. This avoids the MAC backpressuring when the PHY is down.
68    // The device will always send discovery packets to the transports during
69    // initialization, and they have no way of knowing if it's safe to travel
70    // down this route. c2mac == "CHDR to MAC"
71    wire  [63:0]     c2mac_tdata;
72    wire  [3:0]      c2mac_tuser;
73    wire             c2mac_tlast;
74    wire             c2mac_tvalid;
75    wire             c2mac_tready;
76
77    axis_packet_flush #(
78       .WIDTH(64+3), // tdata + tuser
79       .TIMEOUT_W(1), // Not using timeout
80       .FLUSH_PARTIAL_PKTS(0),
81       .PIPELINE("NONE")
82   ) linkup_flush (
83       .clk(bus_clk),
84       .reset(bus_rst),
85       .enable(~link_up), // enable flushing when link down
86       .timeout(1'b0),
87       .flushing(/* not required */),
88       .done(/* not required */),
89       // Input from device/crossbar
90       .s_axis_tdata  ({s_axis_tuser, s_axis_tdata}),
91       .s_axis_tlast  (s_axis_tlast),
92       .s_axis_tvalid (s_axis_tvalid),
93       .s_axis_tready (s_axis_tready),
94       // Output to MAC
95       .m_axis_tdata  ({c2mac_tuser, c2mac_tdata}),
96       .m_axis_tlast  (c2mac_tlast),
97       .m_axis_tvalid (c2mac_tvalid),
98       .m_axis_tready (c2mac_tready)
99   );
100
101
102generate
103   if (PROTOCOL == "10GbE") begin
104      //-----------------------------------------------------------------
105      // 10 Gigabit Ethernet
106      //-----------------------------------------------------------------
107      wire [63:0] xgmii_txd;
108      wire [7:0]  xgmii_txc;
109      wire [63:0] xgmii_rxd;
110      wire [7:0]  xgmii_rxc;
111      wire [7:0]  xgmii_status;
112      wire        xge_phy_resetdone;
113
114      ten_gige_phy ten_gige_phy_i
115      (
116         // Clocks and Reset
117         .areset(areset),                 // Asynchronous reset for entire core.
118         .refclk(gt_refclk),              // Transciever reference clock: 156.25MHz
119         .clk156(gb_refclk),              // Globally buffered core clock: 156.25MHz
120         .dclk(misc_clk),                 // Management/DRP clock: 78.125MHz
121         .sim_speedup_control(1'b0),
122         // GMII Interface (client MAC <=> PCS)
123         .xgmii_txd(xgmii_txd),          // Transmit data from client MAC.
124         .xgmii_txc(xgmii_txc),          // Transmit control signal from client MAC.
125         .xgmii_rxd(xgmii_rxd),          // Received Data to client MAC.
126         .xgmii_rxc(xgmii_rxc),          // Received control signal to client MAC.
127         // Tranceiver Interface
128         .txp(txp),                       // Differential +ve of serial transmission from PMA to PMD.
129         .txn(txn),                       // Differential -ve of serial transmission from PMA to PMD.
130         .rxp(rxp),                       // Differential +ve for serial reception from PMD to PMA.
131         .rxn(rxn),                       // Differential -ve for serial reception from PMD to PMA.
132         // Management: MDIO Interface
133         .mdc(mdc),                      // Management Data Clock
134         .mdio_in(mdio_in),              // Management Data In
135         .mdio_out(mdio_out),            // Management Data Out
136         .mdio_tri(),                     // Management Data Tristate
137         .prtad(5'd4),                    // MDIO address is 4
138         // General IO's
139         .core_status(xgmii_status),     // Core status
140         .resetdone(xge_phy_resetdone),
141         .signal_detect(~sfpp_rxlos),     // Input from PMD to indicate presence of optical input. (Undocumented, but it seems Xilinx expect this to be inverted.)
142         .tx_fault(sfpp_tx_fault),
143         .tx_disable(sfpp_tx_disable)
144      );
145
146      xge_mac_wrapper #(
147        .PORTNUM(PORTNUM),
148        .WISHBONE(1)
149      ) xge_mac_wrapper_i (
150         // XGMII
151         .xgmii_clk(gb_refclk),
152         .xgmii_txd(xgmii_txd),
153         .xgmii_txc(xgmii_txc),
154         .xgmii_rxd(xgmii_rxd),
155         .xgmii_rxc(xgmii_rxc),
156         // MDIO
157         .mdc(mdc),
158         .mdio_in(mdio_in),
159         .mdio_out(mdio_out),
160         // Wishbone I/F
161         .wb_clk_i(bus_clk_div2),
162         .wb_rst_i(bus_rst_div2),
163         .wb_adr_i(wb_adr_i),
164         .wb_cyc_i(wb_cyc_i),
165         .wb_dat_i(wb_dat_i),
166         .wb_stb_i(wb_stb_i),
167         .wb_we_i(wb_we_i),
168         .wb_ack_o(wb_ack_o),
169         .wb_dat_o(wb_dat_o),
170         .wb_int_o(wb_int_o),
171         // Client FIFO Interfaces
172         .sys_clk(bus_clk),
173         .sys_rst(bus_rst),
174         .rx_tdata(m_axis_tdata),
175         .rx_tuser(m_axis_tuser),
176         .rx_tlast(m_axis_tlast),
177         .rx_tvalid(m_axis_tvalid),
178         .rx_tready(m_axis_tready),
179         .tx_tdata(c2mac_tdata),
180         .tx_tuser(c2mac_tuser),                // Bit[3] (error) is ignored for now.
181         .tx_tlast(c2mac_tlast),
182         .tx_tvalid(c2mac_tvalid),
183         .tx_tready(c2mac_tready),
184         // Other
185         .phy_ready(xge_phy_resetdone)
186      );
187
188      assign phy_status  = {8'h00, xgmii_status};
189
190      // Use the PCS Block Lock signal to drive the link_up LED on the FP.
191      // For further details, see Xilinx' PG068, Table 2-11 (core_status[0] signal).
192      synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync (
193         .clk(bus_clk), .rst(1'b0 /* no reset */), .in(xgmii_status[0]), .out(link_up));
194
195
196   end else if (PROTOCOL == "1GbE") begin
197
198      //-----------------------------------------------------------------
199      // 1 Gigabit Ethernet
200      //-----------------------------------------------------------------
201      wire [7:0]  gmii_txd, gmii_rxd;
202      wire        gmii_tx_en, gmii_tx_er, gmii_rx_dv, gmii_rx_er;
203      wire        gmii_clk;
204
205      assign sfpp_tx_disable = 1'b0; // Always on.
206
207      one_gige_phy one_gige_phy_i
208      (
209         .reset(areset),                  // Asynchronous reset for entire core.
210         .independent_clock(bus_clk),
211         // Tranceiver Interface
212         .gtrefclk(gt_refclk),            // Reference clock for MGT: 125MHz, very high quality.
213         .gtrefclk_bufg(gb_refclk),       // Reference clock routed through a BUFG
214         .txp(txp),                       // Differential +ve of serial transmission from PMA to PMD.
215         .txn(txn),                       // Differential -ve of serial transmission from PMA to PMD.
216         .rxp(rxp),                       // Differential +ve for serial reception from PMD to PMA.
217         .rxn(rxn),                       // Differential -ve for serial reception from PMD to PMA.
218         // GMII Interface (client MAC <=> PCS)
219         .gmii_clk(gmii_clk),            // Clock to client MAC.
220         .gmii_txd(gmii_txd),            // Transmit data from client MAC.
221         .gmii_tx_en(gmii_tx_en),        // Transmit control signal from client MAC.
222         .gmii_tx_er(gmii_tx_er),        // Transmit control signal from client MAC.
223         .gmii_rxd(gmii_rxd),            // Received Data to client MAC.
224         .gmii_rx_dv(gmii_rx_dv),        // Received control signal to client MAC.
225         .gmii_rx_er(gmii_rx_er),        // Received control signal to client MAC.
226         // Management: MDIO Interface
227         .mdc(mdc),                      // Management Data Clock
228         .mdio_i(mdio_in),               // Management Data In
229         .mdio_o(mdio_out),              // Management Data Out
230         .mdio_t(),                       // Management Data Tristate
231         .configuration_vector(5'd0),     // Alternative to MDIO interface.
232         .configuration_valid(1'b1),      // Validation signal for Config vector (MUST be 1 for proper functionality...undocumented)
233         // General IO's
234         .status_vector(phy_status),    // Core status.
235         .signal_detect(1'b1 /*Optical module not supported*/) // Input from PMD to indicate presence of optical input.
236      );
237
238      simple_gemac_wrapper #(.RX_FLOW_CTRL(0), .PORTNUM(PORTNUM)) simple_gemac_wrapper_i
239      (
240         .clk125(gmii_clk),
241         .reset(areset),
242
243         .GMII_GTX_CLK(),
244         .GMII_TX_EN(gmii_tx_en),
245         .GMII_TX_ER(gmii_tx_er),
246         .GMII_TXD(gmii_txd),
247         .GMII_RX_CLK(gmii_clk),
248         .GMII_RX_DV(gmii_rx_dv),
249         .GMII_RX_ER(gmii_rx_er),
250         .GMII_RXD(gmii_rxd),
251
252         .sys_clk(bus_clk),
253         .rx_tdata(m_axis_tdata),
254         .rx_tuser(m_axis_tuser),
255         .rx_tlast(m_axis_tlast),
256         .rx_tvalid(m_axis_tvalid),
257         .rx_tready(m_axis_tready),
258         .tx_tdata(c2mac_tdata),
259         .tx_tuser(c2mac_tuser),
260         .tx_tlast(c2mac_tlast),
261         .tx_tvalid(c2mac_tvalid),
262         .tx_tready(c2mac_tready),
263         // MDIO
264         .mdc(mdc),
265         .mdio_in(mdio_in),
266         .mdio_out(mdio_out),
267         .mdio_tri(),
268         // Wishbone I/F
269         .wb_clk_i(bus_clk_div2),
270         .wb_rst_i(bus_rst_div2),
271         .wb_adr_i(wb_adr_i),
272         .wb_cyc_i(wb_cyc_i),
273         .wb_dat_i(wb_dat_o),
274         .wb_stb_i(wb_stb_i),
275         .wb_we_i(wb_we_i),
276         .wb_ack_o(wb_ack_o),
277         .wb_dat_o(wb_dat_i),
278         .wb_int_o(wb_int_o),
279         // Debug
280         .debug_tx(), .debug_rx()
281      );
282
283      // Use the Link Status signal to drive the link_up LED on the FP.
284      // For further details, see Xilinx' PG047, Table 2-76 (status_vector[0]).
285      synchronizer #(.INITIAL_VAL(1'b0)) link_up_sync (
286         .clk(bus_clk), .rst(1'b0 /* no reset */), .in(phy_status[0]), .out(link_up));
287
288
289   end else if (PROTOCOL == "Aurora") begin
290
291      //-----------------------------------------------------------------
292      // Aurora
293      //-----------------------------------------------------------------
294      wire        au_user_clk, au_user_rst, phy_areset;
295      wire [63:0] i_tdata, o_tdata;
296      wire        i_tvalid, i_tready, o_tvalid;
297      wire        channel_up, hard_err, soft_err;
298      wire        mac_clear;
299
300      assign sfpp_tx_disable = 1'b0; // Always on.
301
302      aurora_phy_x1 aurora_phy_i (
303         // Resets
304         .areset(areset | phy_areset),
305         // Clocks
306         .refclk(gt_refclk),
307         .init_clk(misc_clk),
308         .user_clk(au_user_clk),
309         .user_rst(au_user_rst),
310         // GTX Serial I/O
311         .tx_p(txp),
312         .tx_n(txn),
313         .rx_p(rxp),
314         .rx_n(rxn),
315         // AXI4-Stream TX Interface
316         .s_axis_tdata(i_tdata),
317         .s_axis_tvalid(i_tvalid),
318         .s_axis_tready(i_tready),
319         // AXI4-Stream RX Interface
320         .m_axis_tdata(o_tdata),
321         .m_axis_tvalid(o_tvalid),
322         // AXI4-Lite Config Interface: TODO: Hook up to WB->AXI4Lite converter
323         .s_axi_awaddr(32'h0),
324         .s_axi_araddr(32'h0),
325         .s_axi_awvalid(1'b0),
326         .s_axi_awready(),
327         .s_axi_wdata(32'h0),
328         .s_axi_wvalid(1'b0),
329         .s_axi_wstrb(1'b0),
330         .s_axi_wready(),
331         .s_axi_bvalid(),
332         .s_axi_bresp(),
333         .s_axi_bready(1'b1),
334         .s_axi_arready(),
335         .s_axi_arvalid(1'b0),
336         .s_axi_rdata(),
337         .s_axi_rvalid(),
338         .s_axi_rresp(),
339         .s_axi_rready(1'b1),
340         // Status and Error Reporting Interface
341         .channel_up(channel_up),
342         .hard_err(hard_err),
343         .soft_err(soft_err)
344      );
345
346      assign phy_status = {14'd0, hard_err, channel_up};
347
348      wire           bist_gen_en, bist_checker_en, bist_loopback_en;
349      wire           bist_checker_locked;
350      wire [5:0]     bist_gen_rate;
351      wire [47:0]    bist_checker_samps, bist_checker_errors;
352      wire [31:0]    overruns, checksum_errors;
353
354      aurora_axis_mac #(
355         .PHY_ENDIANNESS ("LITTLE"),
356         .PACKET_MODE    (1),
357         .MAX_PACKET_SIZE(1024),
358         .BIST_ENABLED   (1)
359      ) aurora_mac_i (
360         // Clocks and resets
361         .phy_clk(au_user_clk), .phy_rst(au_user_rst),
362         .sys_clk(bus_clk), .sys_rst(bus_rst),
363         .clear(mac_clear),
364         // PHY Interface (Synchronous to phy_clk)
365         .phy_s_axis_tdata(o_tdata),
366         .phy_s_axis_tvalid(o_tvalid),
367         .phy_m_axis_tdata(i_tdata),
368         .phy_m_axis_tvalid(i_tvalid),
369         .phy_m_axis_tready(i_tready),
370         // User Interface (Synchronous to sys_clk)
371         .s_axis_tdata(c2mac_tdata),
372         .s_axis_tlast(c2mac_tlast),
373         .s_axis_tvalid(c2mac_tvalid),
374         .s_axis_tready(c2mac_tready),
375         .m_axis_tdata(m_axis_tdata),
376         .m_axis_tlast(m_axis_tlast),
377         .m_axis_tvalid(m_axis_tvalid),
378         .m_axis_tready(m_axis_tready),
379         // PHY Status Inputs (Synchronous to phy_clk)
380         .channel_up(channel_up),
381         .hard_err(hard_err),
382         .soft_err(soft_err),
383         // Status and Error Outputs (Synchronous to sys_clk)
384         .overruns(overruns),
385         .soft_errors(),
386         .checksum_errors(checksum_errors),
387         .critical_err(mac_crit_err),
388         // BIST Interface (Synchronous to sys_clk)
389         .bist_gen_en(bist_gen_en),
390         .bist_gen_rate(bist_gen_rate),
391         .bist_checker_en(bist_checker_en),
392         .bist_loopback_en(bist_loopback_en),
393         .bist_checker_locked(bist_checker_locked),
394         .bist_checker_samps(bist_checker_samps),
395         .bist_checker_errors(bist_checker_errors)
396      );
397
398       reg mac_crit_err_latch;
399       always @(posedge bus_clk) begin
400          if (bus_rst | mac_clear) begin
401             mac_crit_err_latch <= 1'b0;
402          end else begin
403             if (mac_crit_err_bclk)
404                mac_crit_err_latch <= 1'b1;
405          end
406       end
407
408      assign m_axis_tuser = 4'd0;
409
410      wire        set_stb;
411      wire [3:0]  set_addr, rb_addr;
412      wire [31:0] set_data;
413      reg  [31:0] rb_data;
414
415      settings_bus #(.AWIDTH(8), .DWIDTH(32), .SWIDTH(4)) settings_bus_i (
416         .wb_clk(bus_clk), .wb_rst(bus_rst),
417         .wb_adr_i(wb_adr_i), .wb_dat_i(wb_dat_i),
418         .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_ack_o(wb_ack_o),
419         .strobe(set_stb), .addr(set_addr), .data(set_data)
420      );
421
422      settings_readback #(.AWIDTH(8),.DWIDTH(32), .RB_ADDRW(4)) settings_readback_i (
423         .wb_clk(bus_clk), .wb_rst(bus_rst),
424         .wb_adr_i(wb_adr_i), .wb_stb_i(wb_stb_i), .wb_we_i(wb_we_i), .wb_dat_o(wb_dat_o),
425         .rb_data(rb_data), .rb_addr(rb_addr), .rb_rd_stb()
426      );
427
428      setting_reg #(.my_addr(4'd0), .awidth(4), .width(11), .at_reset(11'h000)) set_core_control_i (
429         .clk(bus_clk), .rst(bus_rst),
430         .strobe(set_stb), .addr(set_addr), .in(set_data),
431         .out({mac_clear, phy_areset, bist_gen_rate, bist_loopback_en, bist_gen_en, bist_checker_en}), .changed()
432      );
433
434      wire channel_up_bclk, hard_err_bclk, soft_err_bclk, mac_crit_err_bclk;
435      synchronizer #(.INITIAL_VAL(1'b0)) channel_up_sync (
436         .clk(bus_clk), .rst(1'b0 /* no reset */), .in(channel_up), .out(channel_up_bclk));
437      synchronizer #(.INITIAL_VAL(1'b0)) hard_err_sync (
438         .clk(bus_clk), .rst(1'b0 /* no reset */), .in(hard_err), .out(hard_err_bclk));
439      synchronizer #(.INITIAL_VAL(1'b0)) soft_err_sync (
440         .clk(bus_clk), .rst(1'b0 /* no reset */), .in(soft_err), .out(soft_err_bclk));
441      synchronizer #(.INITIAL_VAL(1'b0)) mac_crit_err_sync (
442        .clk(bus_clk), .rst(1'b0 /* no reset */), .in(mac_crit_err), .out(mac_crit_err_bclk));
443
444      reg [19:0]  bist_lock_latency;
445      always @(posedge bus_clk) begin
446         if (!bist_checker_en && !bist_checker_locked)
447            bist_lock_latency <= 20'd0;
448         else if (bist_checker_en && !bist_checker_locked)
449            bist_lock_latency <= bist_lock_latency + 20'd1;
450      end
451
452       reg mac_crit_err_latch;
453       always @(posedge bus_clk) begin
454          if (bus_rst | mac_clear) begin
455             mac_crit_err_latch <= 1'b0;
456          end else begin
457             if (mac_crit_err_bclk)
458                mac_crit_err_latch <= 1'b1;
459          end
460       end
461
462      wire [31:0] core_status = {
463         6'h0,                      //[31:26]
464         mac_crit_err_latch,        //[25]
465         1,                         //[24] mmcm_locked_bclk
466         1,                         //[23] gt_pll_locked_bclk
467         0,                         //[22] qpll_refclklost_bclk
468         1,                         //[21] qpll_lock_bclk
469         0,                         //[20] qpll_reset_bclk
470         bist_lock_latency[19:4],   //[19:4]
471         bist_checker_locked,       //[3]
472         soft_err_bclk,             //[2]
473         hard_err_bclk,             //[1]
474         channel_up_bclk            //[0]
475      };
476
477      assign link_up = channel_up_bclk;
478
479      always @(*)
480         case (rb_addr)
481            4'd0:    rb_data = core_status;
482            4'd1:    rb_data = overruns;
483            4'd2:    rb_data = checksum_errors;
484            4'd3:    rb_data = bist_checker_samps[47:16];   //Scale num sample by 2^16
485            4'd4:    rb_data = bist_checker_errors[31:0];   //Dont scale errors
486            default: rb_data = 32'h0;
487         endcase // case (rb_addr)
488
489   end else begin
490
491      //Invalid protocol
492
493   end
494endgenerate
495
496   //-----------------------------------------------------------------
497   // Activity detector
498   //-----------------------------------------------------------------
499
500   pulse_stretch act_pulse_str_i (
501     .clk(bus_clk),
502     .rst(bus_rst | ~link_up),
503     .pulse((s_axis_tvalid & s_axis_tready) | (m_axis_tvalid & m_axis_tready)),
504     .pulse_stretched(activity)
505   );
506
507endmodule
508
509