summaryrefslogtreecommitdiffstats
path: root/pwrseq.v
blob: c4f9f5ad8c55e13dc429b212071cc5cfff505a4b (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
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
OpenPOWER on IntegriCloud