/* * an.v * * Copyright 2021 Mind Chasers Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * function: Auto Negotiation * * Notes: a simplified version of AN suitable for SGMII only (not 1000BASE-SX) */ `timescale 1ns /10ps module an( input rstn, input phy_resetn, // The external PHY has its reset signal asserted input clk, // AN input [1:0] phy_type, // SGMII==0, SX=1, SMA=3 input pulse_1_6ms, // SGMII input pulse_10ms, // SX input [1:0] fixed_speed, input an_disable, output reg an_duplex, output reg [1:0] an_speed, output reg an_link_up, output reg [15:0] tx_config_reg, output reg phy_up, input rx_k_m1, input rx_k_m2, input rx_k_m3, input rx_k_m4, input [7:0] rx_data_m1, input [7:0] rx_data_m2, input [7:0] rx_data_m3, input [7:0] rx_data_m4 // Debug ); `include "sgmii_params.v" `include "ethernet_params.v" localparam PHY_TYPE_SGMII = 2'b00, PHY_TYPE_SX = 2'b01, PHY_TYPE_RSVD = 2'b10, PHY_TYPE_SMA = 2'b11; localparam AN_TYPE_SX = 1'b0, AN_TYPE_SGMII = 1'b1; localparam AN_ST_DISABLE=4'h0, AN_ST_ENABLE=4'h1, AN_ST_RESTART=4'h2, AN_ST_ABILITY_DETECT=4'h3, AN_ST_ACK_DETECT=4'h4, AN_ST_COMPLETE_ACK=4'h5, AN_ST_IDLE_DETECT=4'h6, AN_ST_LINK_OK=4'h7; // AN reg [2:0] an_state; wire an_ability_detect; wire an_link_timer_pulse; reg rx_config_detect; reg [15:0] rx_config_reg, tx_config_reg; reg [1:0] rx_config_cnt; // use to count consecutive rx config_regs /* * SGMII Auto Negotiation State Machine * Look for configuration /C/ ordered set * /C/ is Alternating /C1/ and /C2/ * /C1/: /K28.5/D21.5(0xb5)/Config_Reg * /C2/: /K28.5/D2.2(0x42)/Config_Reg * Config Reg: Low High */ always @(posedge clk or negedge rstn) if (!rstn) begin an_link_up <= 1'b0; an_duplex <= 1'b0; an_speed <= SGMII_SPEED_RSVD; phy_up <= 1'b0; end else if ( !phy_resetn ) begin an_link_up <= 1'b0; an_duplex <= 1'b0; an_speed <= SGMII_SPEED_RSVD; phy_up <= 1'b0; end else if ( an_disable ) begin phy_up <= 1'b1; end // D21.5 is part of config ( M2 has low, M1 has high ) else if (!rx_k_m1 && !rx_k_m2 && !rx_k_m3 && rx_data_m3 == D21_5 && rx_k_m4 && rx_data_m4 == K28_5 ) begin an_link_up <= rx_data_m1[7]; an_duplex <= rx_data_m1[4]; an_speed <= rx_data_m1[3:2]; phy_up <= 1'b0; end // IDLE2 1:0xBC, 0:0x50 else if ( !rx_k_m1 && rx_data_m1 == D16_2 && rx_k_m2 == 1'b1 && rx_data_m2 == K28_5 ) phy_up <= 1'b1; assign an_ability_detect = (rx_config_cnt == 2'd3 && rx_config_reg != 16'h0000 ); assign link_timer_pulse = (phy_type == PHY_TYPE_SGMII && pulse_1_6ms) || (phy_type == PHY_TYPE_SX && pulse_10ms); endmodule