File: qsfp_led_controller.v

package info (click to toggle)
uhd 4.8.0.0%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 183,172 kB
  • sloc: cpp: 279,415; python: 109,850; ansic: 103,348; vhdl: 57,230; tcl: 20,007; xml: 8,581; makefile: 2,863; sh: 2,797; pascal: 230; javascript: 120; csh: 94; asm: 20; perl: 11
file content (146 lines) | stat: -rw-r--r-- 3,948 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//
// Copyright 2023 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: qsfp_led_controller
//
// Description:
//
//   Translate the active and link status LED signals on FPGA to control port
//   requests in order to transfer them to the CPLD, which drives the LEDs.
//
// Parameters:
//
//   LED_REGISTER_ADDRESS : Address of LED register within CPLD.
//

`default_nettype none


module qsfp_led_controller #(
  parameter LED_REGISTER_ADDRESS = 0
) (
  // Common ControlPort signals
  input wire ctrlport_clk,
  input wire ctrlport_rst,

  // ControlPort request
  output reg         m_ctrlport_req_wr,
  output wire        m_ctrlport_req_rd,
  output wire [19:0] m_ctrlport_req_addr,
  output wire [31:0] m_ctrlport_req_data,
  output wire [ 3:0] m_ctrlport_req_byte_en,

  // ControlPort response
  input wire        m_ctrlport_resp_ack,
  input wire [ 1:0] m_ctrlport_resp_status,
  input wire [31:0] m_ctrlport_resp_data,

  // QSFP port LED signals
  input wire [3:0] qsfp0_led_active,
  input wire [3:0] qsfp0_led_link,
  input wire [3:0] qsfp1_led_active,
  input wire [3:0] qsfp1_led_link
);

  `include "../../lib/rfnoc/core/ctrlport.vh"

  //----------------------------------------------------------
  // Transfer LED signals to local clock domain
  //----------------------------------------------------------

  wire [15:0] led_combined;

  synchronizer #(
    .WIDTH            (16),
    .STAGES           (2),
    .INITIAL_VAL      (0),
    .FALSE_PATH_TO_IN (1)
  ) synchronizer_i (
    .clk (ctrlport_clk),
    .rst (ctrlport_rst),
    .in  ({qsfp1_led_active, qsfp1_led_link, qsfp0_led_active, qsfp0_led_link}),
    .out (led_combined)
  );

  //----------------------------------------------------------
  // State machine to initialize and update LED status
  //----------------------------------------------------------

  localparam COUNT_W   = 8;
  localparam MAX_COUNT = 2**COUNT_W-1;

  // This counter ensures the we have a delay before we attempt to initialize
  // the LED state and limits the rate at which the LEDs update.
  reg [COUNT_W-1:0] startup_count = 0;

  localparam ST_INIT     = 0;
  localparam ST_WRITE    = 1;
  localparam ST_WAIT_ACK = 2;
  localparam ST_IDLE     = 3;

  reg [1:0] state = ST_INIT;

  reg [15:0] led_combined_delayed;

  always @(posedge ctrlport_clk) begin
    m_ctrlport_req_wr    <= 0;
    led_combined_delayed <= led_combined;

    case (state)
      ST_INIT : begin
        // Set LED state after a delay
        startup_count <= startup_count + 1;
        if (startup_count == MAX_COUNT) begin
          state <= ST_WRITE;
        end
      end

      ST_WRITE : begin
        // Start an LED update request
        m_ctrlport_req_wr <= 1;
        state             <= ST_WAIT_ACK;
      end

      ST_WAIT_ACK : begin
        // Wait for the acknowledgment from the bus
        if (m_ctrlport_resp_ack) begin
          if (m_ctrlport_resp_status != CTRL_STS_OKAY) begin
            // Status was bad, so try again after a delay
            state <= ST_INIT;
          end else begin
            state <= ST_IDLE;
          end
        end
      end

      ST_IDLE : begin
        // Wait here until the LED status changes
        if (led_combined != led_combined_delayed) begin
          state <= ST_INIT;
        end
      end
    endcase

    if (ctrlport_rst) begin
      state                <= ST_INIT;
      startup_count        <= 0;
      m_ctrlport_req_wr    <= 0;
      led_combined_delayed <= 0;
    end
  end

  //----------------------------------------------------------
  // Static ControlPort assignments
  //----------------------------------------------------------

  assign m_ctrlport_req_rd      = 0;
  assign m_ctrlport_req_byte_en = 4'b0011;
  assign m_ctrlport_req_addr    = LED_REGISTER_ADDRESS;
  assign m_ctrlport_req_data    = {16'b0, led_combined_delayed};

endmodule


`default_nettype wire