From b49be0230de6f2e1a2a893b6eb5722429f78ec7f Mon Sep 17 00:00:00 2001
From: mindchasers <privateisland@mindchasers.com>
Date: Tue, 2 Mar 2021 12:28:04 -0500
Subject: an: encapsulate a simpliied version of SGMII auto negotiation

---
 source/an.v | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
 create mode 100644 source/an.v

(limited to 'source')

diff --git a/source/an.v b/source/an.v
new file mode 100644
index 0000000..18b5d95
--- /dev/null
+++ b/source/an.v
@@ -0,0 +1,122 @@
+/*
+ *       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
-- 
cgit v1.2.3-8-gadcc