summaryrefslogtreecommitdiffstats
path: root/pwrseq.v
diff options
context:
space:
mode:
Diffstat (limited to 'pwrseq.v')
-rw-r--r--pwrseq.v207
1 files changed, 207 insertions, 0 deletions
diff --git a/pwrseq.v b/pwrseq.v
new file mode 100644
index 0000000..c4f9f5a
--- /dev/null
+++ b/pwrseq.v
@@ -0,0 +1,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 \ No newline at end of file
OpenPOWER on IntegriCloud