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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
// Copyright © 2017 Raptor Engineering, LLC
// Copyright © 2017, International Business Machines Corp.
// All Rights Reserved
//
// See LICENSE file for licensing details
module pwrseq(
output wire [rail_size - 1:0] EN,
input wire [rail_size - 1:0] PGOOD_A,
input wire SYSEN_A,
output wire SYSGOOD,
inout wire SCL,
inout wire SDA,
input wire CLK_IN
);
parameter [31:0] rail_size;
// Input output buffers and synchronizers
reg [rail_size - 1:0] EN_BUF = 1'b0;
reg [rail_size - 1:0] PGOOD = 1'b0;
reg [rail_size - 1:0] PGOOD_S = 1'b0;
reg SYSEN = 1'b0;
reg SYSEN_S = 1'b0;
reg SYSGOOD_BUF = 1'b0;
// Sequencer State Machine
parameter [2:0] idleon = 0;
parameter [2:0] shifton = 1;
parameter [2:0] waitpgood = 2;
parameter [2:0] waiten = 3;
parameter [2:0] idleoff = 4;
parameter [2:0] shiftoff = 5;
parameter [2:0] waitoff = 6;
reg [2:0] state = idleoff;
reg ERR = 1'b0;
reg [15:0] err_msg = 1'b1;
parameter all_on = 1'b1;
parameter all_off = 1'b0;
// Clocks and timers
parameter counter_size = 20;
reg [counter_size - 1:0] T_COUNT;
// t_max_wait is max delay from Enable assert to Pgood assert (200 ms assumption 4.125MHz clk)
parameter t_max_wait = 825000;
// t_delay is delay from Pgood assert to next Enable assert (1ms assumption 4.125MHz clk)
parameter t_delay = 4125;
//I2C signals
wire i2c_read_req;
reg [7:0] i2c_data_to_master = 8'b00000000;
wire [7:0] i2c_data_from_master;
wire i2c_data_valid;
wire i2c_rst = 1'b0;
reg [7:0] i2c_reg_cur = 8'b00000000;
parameter i2c_addr = 7'b0110001;
parameter i2c_pg_reg_addr1 = 8'b00000001;
parameter i2c_pg_reg_addr2 = i2c_pg_reg_addr1 + 1;
parameter i2c_status_reg_addr = i2c_pg_reg_addr2 + 1;
I2C_slave #(i2c_addr)
I2C_SLAVE(
SCL,
SDA,
CLK_IN,
i2c_rst,
i2c_read_req,
i2c_data_to_master,
i2c_data_valid,
i2c_data_from_master
);
// Handle I2C
// 2 8-bit registers with PGOOD state on error
always @(posedge CLK_IN) begin
//return high byte with any memory address, loop on any consecutive reads
if (i2c_data_valid == 1'b1) begin
i2c_reg_cur <= i2c_data_from_master;
end
else if (i2c_read_req == 1'b1) begin
i2c_reg_cur <= i2c_reg_cur + 1;
end
case(i2c_reg_cur)
i2c_pg_reg_addr1 : begin
i2c_data_to_master <= err_msg[15:8];
end
i2c_pg_reg_addr2 : begin
i2c_data_to_master <= err_msg[7:0];
end
i2c_status_reg_addr : begin
i2c_data_to_master <= {6'b000000,SYSEN,SYSGOOD_BUF};
end
default : begin
i2c_data_to_master <= 8'b00000000;
end
endcase
end
// Power Sequencer state machine
always @(posedge CLK_IN) begin
// Increase counter
T_COUNT <= T_COUNT + 1;
// Synchronize Asynchronous inputs to clock
PGOOD_S <= PGOOD_A;
PGOOD <= PGOOD_S;
SYSEN_S <= SYSEN_A;
SYSEN <= SYSEN_S;
// Decide next state
case(state)
idleoff : begin
//Only leave idle off if system enable active and no error
if (ERR == 1'b1) begin
state <= idleoff;
end
else if (SYSEN == 1'b1) begin
state <= shifton;
end else begin
state <= idleoff;
end
end
shifton : begin
// enable next power rail, reset counter, wait for pgood
EN_BUF[rail_size - 1:1] <= EN_BUF[rail_size - 2:0];
EN_BUF[0] <= 1'b1;
T_COUNT <= {(((counter_size - 1))-((0))+1){1'b0}};
state <= waitpgood;
end
waitpgood : begin
// Wait for enabled power rail's PGOOD, after time with no pgood, error
if (T_COUNT > t_max_wait) begin
ERR <= 1'b1;
err_msg <= {16{1'b0}};
err_msg[rail_size - 1:0] <= EN_BUF & PGOOD;
state <= shiftoff;
end
else if ((EN_BUF & PGOOD) == all_on) begin
state <= idleon;
end
else if (((EN_BUF & PGOOD) == EN_BUF)) begin
T_COUNT <= {(((counter_size - 1))-((0))+1){1'b0}};
state <= waiten;
end else begin
state <= waitpgood;
end
end
waiten : begin
// delay between last pgood and next enable
if (T_COUNT > t_delay) begin
T_COUNT <= {(((counter_size - 1))-((0))+1){1'b0}};
state <= shifton;
end else begin
state <= waiten;
end
end
idleon : begin
// stay in idle on unless power rail goes down (error) or system enable removed
SYSGOOD_BUF <= 1'b1;
if ((!(PGOOD == all_on))) begin
ERR <= 1'b1;
err_msg <= {16{1'b0}};
err_msg[rail_size - 1:0] <= PGOOD;
end
if (((SYSEN == 1'b0) || (ERR == 1'b1))) begin
SYSGOOD_BUF <= 1'b0;
state <= shiftoff;
end else begin
state <= idleon;
end
end
shiftoff : begin
// Turn off enable for next power rail
EN_BUF[rail_size - 2:0] <= EN_BUF[rail_size - 1:1];
EN_BUF[rail_size - 1] <= 1'b0;
if ((EN_BUF == all_off)) begin
state <= idleoff;
end else begin
T_COUNT <= {(((counter_size - 1))-((0))+1){1'b0}};
state <= waitoff;
end
end
waitoff : begin
// in controlled shutdown, delay between disabling power rails
if (ERR == 1'b1) begin
state <= shiftoff;
//LED_BUF <= "10";
end
else if (T_COUNT > t_delay) begin
state <= shiftoff;
//LED_BUF <= "10";
end else begin
state <= waitoff;
end
end
endcase
end
// Output enable buffer to pins
assign EN = ~(EN_BUF);
assign i2c_rst = 1'b0;
assign SYSGOOD = SYSGOOD_BUF;
endmodule
|