summaryrefslogtreecommitdiffhomepage
path: root/source/an.v
blob: 18b5d954bc8165304fa3e7b057f130ad506150e8 (plain)
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
/*
 *       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