Files
max2771-raw-ethernet-recorder/targets/genesys2/rtl/phy_init_rtl8211e.sv
T

86 lines
3.5 KiB
Systemverilog

`default_nettype none
// The Genesys 2 straps the RTL8211E-VL for auto-negotiation and PHY address 1.
// After the mandatory post-reset settling time, this controller polls PHYSR
// (register 0x11) and permits transmit only for resolved 1000 Mb/s full duplex.
module phy_init #(
parameter int unsigned CLK_HZ = 125_000_000,
parameter int unsigned SETTLE_MS = 30,
parameter int unsigned POLL_MS = 100
) (
input wire logic clk,
input wire logic rst,
input wire logic phy_reset_complete,
output logic mdio_start,
output logic mdio_write,
output logic [4:0] mdio_phy_address,
output logic [4:0] mdio_register_address,
output logic [15:0] mdio_write_data,
input wire logic mdio_busy,
input wire logic mdio_done,
input wire logic [15:0] mdio_read_data,
output logic initialization_complete,
output logic link_ready,
output logic [63:0] link_down_events
);
localparam longint unsigned SETTLE_CYCLES = (CLK_HZ / 1000) * SETTLE_MS;
localparam longint unsigned POLL_CYCLES = (CLK_HZ / 1000) * POLL_MS;
localparam int unsigned TIMER_W = $clog2(((POLL_CYCLES > SETTLE_CYCLES) ? POLL_CYCLES : SETTLE_CYCLES) + 1);
typedef enum logic [2:0] {I_WAIT_RESET, I_SETTLE, I_START, I_WAIT_MDIO, I_POLL_WAIT} istate_t;
istate_t state;
logic [TIMER_W-1:0] timer;
logic new_link_ready;
always_comb begin
mdio_write = 1'b0;
mdio_phy_address = 5'd1;
mdio_register_address = 5'h11;
mdio_write_data = 16'd0;
new_link_ready = (mdio_read_data[15:14] == 2'b10) &&
mdio_read_data[13] && mdio_read_data[11] && mdio_read_data[10];
end
always_ff @(posedge clk) begin
if (rst) begin
state <= I_WAIT_RESET;
timer <= '0;
mdio_start <= 1'b0;
initialization_complete <= 1'b0;
link_ready <= 1'b0;
link_down_events <= 64'd0;
end else begin
mdio_start <= 1'b0;
case (state)
I_WAIT_RESET: begin
link_ready <= 1'b0;
if (phy_reset_complete) begin timer <= '0; state <= I_SETTLE; end
end
I_SETTLE: begin
if (timer == SETTLE_CYCLES-1) begin timer <= '0; state <= I_START; end
else timer <= timer + {{(TIMER_W-1){1'b0}},1'b1};
end
I_START: begin
if (!mdio_busy) begin mdio_start <= 1'b1; state <= I_WAIT_MDIO; end
end
I_WAIT_MDIO: begin
if (mdio_done) begin
initialization_complete <= 1'b1;
if (link_ready && !new_link_ready)
link_down_events <= link_down_events + 64'd1;
link_ready <= new_link_ready;
timer <= '0;
state <= I_POLL_WAIT;
end
end
I_POLL_WAIT: begin
if (timer == POLL_CYCLES-1) begin timer <= '0; state <= I_START; end
else timer <= timer + {{(TIMER_W-1){1'b0}},1'b1};
end
default: state <= I_WAIT_RESET;
endcase
end
end
endmodule
`default_nettype wire