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
|