URL
https://opencores.org/ocsvn/powerseq/powerseq/trunk
Subversion Repositories powerseq
[/] [powerseq/] [trunk/] [example2.vhd] - Rev 2
Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- Engineer: Istvan Nagy -- Create Date: 10/06/2024 10:10:13 AM -- License: 0BSD, no restrictions for use, no need to publish modified versions. -- The BSD 0-clause license: Copyright (C) 2024 by Istvan Nagy buenoshun@gmail.com -- Permission to use, copy, modify, and/or distribute this software for any purpose -- with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND -- THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. -- Module Name: example - Behavioral -- Target devices: Michorchip Igloo preferred -- This code shows how a sequencer is typically used on a complex server motherboard. -- This code would be instantiated into a FPGA top level VHDL file, that has other -- logic too, that are not power management related. Signals coming from the X86 and -- the BMC should be double-flopped on the top-level FPGA code file. -- Each power domain needs a separate powerseq block instantiated here. -- On your board the rail assignments will be totally different! Do not reuse as is! -- For every project this file is to be heavily modified or completely rewritten. This -- is not the main reusable open source powerseq code, just an example use case. -- Synthesis statistics: 2992 LUTs, and 1167 register bits ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; --entity header ---------------------------------------------------------------- entity example is Port ( --System signals for FPGA glue logic clk : in std_logic; --25MHz clock reset_n : in std_logic; --FPGA reset, needs 1ms from standby 3.3V on forcepoweron : in std_logic; --from dip switch, avoid failure response pfailure : out std_logic; --assers during failure --1 if one or more railes failed. pseqstate_out : out std_logic_vector(7 downto 0); --we can monitor status through a pin with TopJtag ALL_PWR_ON_LED_N : out std_logic; PWRFAIL_LED_N : out std_logic; --rails: --BMC POWER RAILS VCC_BMC_1V0_ON : out std_logic; VCC_BMC_1V0_PG : in std_logic; VCC_BMC_1V5_ON : out std_logic; VCC_BMC_1V5_PG : in std_logic; --PCH POWER RAILS CONTROL VCC_5V0_ENA : out std_logic; VCC_5V0_PG : in std_logic; P1V0_PCH_SBY_EN : out std_logic; P1V0_PCH_SBY_PG : in std_logic; P1V8_PCH_SBY_EN : out std_logic; P1V8_PCH_SBY_PG : in std_logic; P3V3_S0_EN : out std_logic; P3V3_S0_PG : in std_logic; P1V5_PCH_S0_EN : out std_logic; P1V5_PCH_S0_PG : in std_logic; P1V0_PCH_S0_EN : out std_logic; P1V0_PCH_S0_PG : in std_logic; --CPU POWER RAILS CONTROL VCORECPU1_EN : out std_logic; VCORECPU1_PG : in std_logic; VCCSA_CPU1_EN : out std_logic; VCCSA_CPU1_PG : in std_logic; P1V5_CPU1_EN : out std_logic; P1V5_CPU1_PG : in std_logic; P1V05_CPU1_EN : out std_logic; P1V05_CPU1_PG : in std_logic; VCORECPU2_EN : out std_logic; VCORECPU2_PG : in std_logic; VCCSA_CPU2_EN : out std_logic; VCCSA_CPU2_PG : in std_logic; P1V5_CPU2_EN : out std_logic; P1V5_CPU2_PG : in std_logic; P1V05_CPU2_EN : out std_logic; P1V05_CPU2_PG : in std_logic; --Other device POWER RAILS CONTROL PSU_ON : out std_logic; PSU12V_PG : in std_logic; P1V8_SSD_EN : out std_logic; P1V8_SSD_PG : in std_logic; P1V2_SSD_EN : out std_logic; P1V2_SSD_PG : in std_logic; --PCH POWER MANAGEMENT GLUE LOGIC PCH_RSMRST_N : out std_logic; CPU1_PROCHOT_N : in std_logic; CPU1_THERMTRIP_N : in std_logic; CPU1_CATERR_N : in std_logic; CPU2_PROCHOT_N : in std_logic; CPU2_THERMTRIP_N : in std_logic; CPU2_CATERR_N : in std_logic; CKG_PLL_LOCK : in std_logic; CKG_CLKEN : out std_logic; PCH_PWRBTN_N : out std_logic; PCH_CPUPWRGD : out std_logic; PCH_DRAMPWRGD : out std_logic; PCH_PWROK : out std_logic; PCH_RSTBTN_N : out std_logic; PCH_SLPS3_N : in std_logic; PCH_SLPS5_N : in std_logic; PCH_SLPS4_N : in std_logic; PCH_SYSPWROK : out std_logic; PLTRST_N : in std_logic; --POWER MASTER BMC LOGIC PENA_ALL_BMC : in std_logic; --power master ordered the sequence to commence on PGD_ALL_BMC : out std_logic; --tell the power master that all is on BMC_TO_CPU_RST_N : in std_logic; BMC_RST_N : out std_logic; --reset --other RST_SSD_N : out std_logic; RST_PCIESLT1_N : out std_logic; RST_PCIESLT2_N : out std_logic; RST_PCIESLT3_N : out std_logic; RST_PCIESLT4_N : out std_logic; MEMA_THERM_N : in std_logic; MEMB_THERM_N : in std_logic; MEMC_THERM_N : in std_logic; MEMD_THERM_N : in std_logic ); end example; --architecture start ------------------------------------------------------------ architecture Behavioral of example is -- INTERNAL SIGNALS ------------------------------------------------------------- SIGNAL PSEQ_RAIL_PGa : std_logic_vector(127 downto 0); --map to rails SIGNAL PSEQ_RAIL_ENa : std_logic_vector(127 downto 0); --map to rails SIGNAL failed_railsa : std_logic_vector(255 downto 0); --bits=1 for failed rails SIGNAL tick_outa : std_logic; --available if needed outside, 1pulse in every several thousand clk SIGNAL PSEQ_RAIL_PGb : std_logic_vector(127 downto 0); --map to rails SIGNAL PSEQ_RAIL_ENb : std_logic_vector(127 downto 0); --map to rails SIGNAL failed_railsb : std_logic_vector(255 downto 0); --bits=1 for failed rails SIGNAL pfailurea : std_logic; SIGNAL pfailureb : std_logic; SIGNAL tick_outb : std_logic; --available if needed outside, 1pulse in every several thousand clk SIGNAL thermal_na : std_logic; SIGNAL pseqstate_outa : std_logic_vector(3 downto 0); SIGNAL all_pgooda : std_logic; SIGNAL all_ona : std_logic; SIGNAL thermal_nb : std_logic; SIGNAL pseqstate_outb : std_logic_vector(3 downto 0); SIGNAL all_pgoodb : std_logic; SIGNAL all_onb : std_logic; SIGNAL dummy1 : std_logic; SIGNAL PCH_RSTBTN_N1 : std_logic; SIGNAL x86_state : std_logic_vector(2 downto 0); SIGNAL delaysig_out1 : std_logic; SIGNAL delaysig_in1 : std_logic; SIGNAL delaycounter1 : std_logic_vector(19 downto 0); SIGNAL delaysig_out2 : std_logic; SIGNAL delaysig_in2 : std_logic; SIGNAL delaycounter2 : std_logic_vector(19 downto 0); SIGNAL delaysig_out3 : std_logic; SIGNAL delaysig_in3 : std_logic; SIGNAL delaycounter3 : std_logic_vector(23 downto 0); SIGNAL delaysig_out4 : std_logic; SIGNAL delaysig_in4 : std_logic; SIGNAL delaycounter4 : std_logic_vector(19 downto 0); SIGNAL delaysig_out5 : std_logic; SIGNAL delaysig_in5 : std_logic; SIGNAL delaycounter5 : std_logic_vector(19 downto 0); --------- COMPONENT DECLARATIONS (introducing the IPs) -------------------------- COMPONENT pseq_3redundant PORT( clk : IN std_logic; reset_n : IN std_logic; forcepoweron : IN std_logic; PSEQ_RAIL_PG : IN std_logic_vector(127 downto 0); thermal_n : IN std_logic; all_on : IN std_logic; PSEQ_RAIL_EN : OUT std_logic_vector(127 downto 0); failed_rails : OUT std_logic_vector(255 downto 0); pfailure : OUT std_logic; tick_out : OUT std_logic; pseqstate_out : OUT std_logic_vector(3 downto 0); all_pgood : OUT std_logic ); END COMPONENT; --architecture body start ------------------------------------------------------- begin --First sequencer for S5 standby power domain rails: ############################# --This just turns on as soon as possible, not controlled --Trying to follow this sequence: --1v5_bmc -> 1v0_bmc -> 1v8_pch_sby -> 1v0_pch_sby -> rsmrst Inst_pseq_3redundanta: pseq_3redundant PORT MAP( clk => clk, reset_n => reset_n, forcepoweron => forcepoweron, PSEQ_RAIL_EN => PSEQ_RAIL_ENa, PSEQ_RAIL_PG => PSEQ_RAIL_PGa, thermal_n => thermal_na, failed_rails => failed_railsa, pfailure => pfailurea, tick_out => tick_outa, pseqstate_out => pseqstate_outa, all_on => '1', --always on all_pgood => dummy1 ); -- Rail assignments: --enables VCC_BMC_1V5_ON <= PSEQ_RAIL_ENa(0); VCC_BMC_1V0_ON <= PSEQ_RAIL_ENa(1); P1V8_PCH_SBY_EN <= PSEQ_RAIL_ENa(2); P1V0_PCH_SBY_EN <= PSEQ_RAIL_ENa(3); delaysig_in1 <= PSEQ_RAIL_ENa(4); -- <= PSEQ_RAIL_ENa(127 downto 5); unused --powergood PSEQ_RAIL_PGa(0) <= VCC_BMC_1V5_PG; PSEQ_RAIL_PGa(1) <= VCC_BMC_1V0_PG; PSEQ_RAIL_PGa(2) <= P1V8_PCH_SBY_PG; PSEQ_RAIL_PGa(3) <= P1V0_PCH_SBY_PG; PSEQ_RAIL_PGa(4) <= delaysig_out1; PSEQ_RAIL_PGa(127 downto 5) <= (others => '1'); --unused --system signals for seq 1: thermal_na <= '1'; --not used in this power domain --simple DELAY1: process ( reset_n, clk, delaysig_in1 ) begin if ( reset_n='0' or delaysig_in1='0') then delaysig_out1 <= '0'; delaycounter1 <= (others => '0'); elsif (clk'event and clk='1') then if ( delaycounter1 = "01111010000100100000" ) then --after 20msec (40ns clk period) delaysig_out1 <= '1'; delaycounter1 <= delaycounter1; --stop counting else delaycounter1 <= delaycounter1 +1; delaysig_out1 <= '0'; end if; end if; end process; BMC_RST_N <= delaysig_out1; --we can let them know 20ms after all power is good to come out of reset PCH_RSMRST_N <= delaysig_out1; --Second sequencer for S0 fully-on power domain rails: ############################# --this one turns on or off as the BMC commands it. --Trying to follow this sequence: --12v -> 5v -> 3.3v -> PCH1v5 -> PCH1v0 -> 1v5mem -> drampwrgd -> 1v0cpu -> vcorecpu -> vccsacpu -> 100ms -> pchpwrok -> plllock -> 20ms -> cpupwrgd -> 20ms -> syspwrok Inst_pseq_3redundantb: pseq_3redundant PORT MAP( clk => clk, reset_n => reset_n, forcepoweron => forcepoweron, PSEQ_RAIL_EN => PSEQ_RAIL_ENb, PSEQ_RAIL_PG => PSEQ_RAIL_PGb, thermal_n => thermal_nb, failed_rails => failed_railsb, pfailure => pfailureb, tick_out => tick_outb, pseqstate_out => pseqstate_outb, all_on => all_onb, all_pgood => all_pgoodb ); -- Rail assignments: --enables PSU_ON <= PSEQ_RAIL_ENb(0); VCC_5V0_ENA <= PSEQ_RAIL_ENb(1); P3V3_S0_EN <= PSEQ_RAIL_ENb(2); P1V5_PCH_S0_EN <= PSEQ_RAIL_ENb(3); P1V0_PCH_S0_EN <= PSEQ_RAIL_ENb(4); P1V5_CPU1_EN <= PSEQ_RAIL_ENb(5); P1V5_CPU2_EN <= PSEQ_RAIL_ENb(6); PCH_DRAMPWRGD <= PSEQ_RAIL_ENb(7); VCORECPU1_EN <= PSEQ_RAIL_ENb(8); VCORECPU2_EN <= PSEQ_RAIL_ENb(9); VCCSA_CPU1_EN <= PSEQ_RAIL_ENb(10); VCCSA_CPU2_EN <= PSEQ_RAIL_ENb(11); delaysig_in3 <= PSEQ_RAIL_ENb(12); PCH_PWROK <= PSEQ_RAIL_ENb(13); CKG_CLKEN <= PSEQ_RAIL_ENb(14); delaysig_in4 <= PSEQ_RAIL_ENb(15); PCH_CPUPWRGD <= PSEQ_RAIL_ENb(16); delaysig_in5 <= PSEQ_RAIL_ENb(17); PCH_SYSPWROK <= PSEQ_RAIL_ENb(18); -- <= PSEQ_RAIL_ENb(127 downto 19); unused --powergood PSEQ_RAIL_PGb(0) <= PSU12V_PG; PSEQ_RAIL_PGb(1) <= VCC_5V0_PG; PSEQ_RAIL_PGb(2) <= P3V3_S0_PG; PSEQ_RAIL_PGb(3) <= P1V5_PCH_S0_PG; PSEQ_RAIL_PGb(4) <= P1V0_PCH_S0_PG; PSEQ_RAIL_PGb(5) <= P1V5_CPU1_PG; PSEQ_RAIL_PGb(6) <= P1V5_CPU2_PG; PSEQ_RAIL_PGb(7) <= '1'; PSEQ_RAIL_PGb(8) <= VCORECPU1_PG; PSEQ_RAIL_PGb(9) <= VCORECPU2_PG; PSEQ_RAIL_PGb(10) <= VCCSA_CPU1_PG; PSEQ_RAIL_PGb(11) <= VCCSA_CPU2_PG; PSEQ_RAIL_PGb(12) <= delaysig_out3; PSEQ_RAIL_PGb(13) <= '1'; PSEQ_RAIL_PGb(14) <= CKG_PLL_LOCK; PSEQ_RAIL_PGb(15) <= delaysig_out4; PSEQ_RAIL_PGb(16) <= '1'; PSEQ_RAIL_PGb(17) <= delaysig_out5; PSEQ_RAIL_PGb(18) <= '1'; PSEQ_RAIL_PGb(127 downto 19) <= (others => '1'); --unused --system signals for seq 2: thermal_nb <= CPU1_PROCHOT_N AND CPU1_THERMTRIP_N AND CPU1_CATERR_N AND CPU2_PROCHOT_N AND CPU2_THERMTRIP_N AND CPU2_CATERR_N AND MEMA_THERM_N AND MEMB_THERM_N AND MEMC_THERM_N AND MEMD_THERM_N; --if any of these pulses low, we do a thermal shutdown in S0 --simple DELAY3: process ( reset_n, clk, delaysig_in3 ) begin if ( reset_n='0' or delaysig_in3='0') then delaysig_out3 <= '0'; delaycounter3 <= (others => '0'); elsif (clk'event and clk='1') then if ( delaycounter3 = "001001100010010110100000" ) then --after 100msec (40ns clk period) delaysig_out3 <= '1'; delaycounter3 <= delaycounter3; --stop counting else delaycounter3 <= delaycounter3 +1; delaysig_out3 <= '0'; end if; end if; end process; --simple DELAY4: process ( reset_n, clk, delaysig_in4 ) begin if ( reset_n='0' or delaysig_in4='0') then delaysig_out4 <= '0'; delaycounter4 <= (others => '0'); elsif (clk'event and clk='1') then if ( delaycounter4 = "01111010000100100000" ) then --after 20msec (40ns clk period) delaysig_out4 <= '1'; delaycounter4 <= delaycounter4; --stop counting else delaycounter4 <= delaycounter4 +1; delaysig_out4 <= '0'; end if; end if; end process; --simple DELAY5: process ( reset_n, clk, delaysig_in5 ) begin if ( reset_n='0' or delaysig_in5='0') then delaysig_out5 <= '0'; delaycounter5 <= (others => '0'); elsif (clk'event and clk='1') then if ( delaycounter5 = "01111010000100100000" ) then --after 20msec (40ns clk period) delaysig_out5 <= '1'; delaycounter5 <= delaycounter5; --stop counting else delaycounter5 <= delaycounter5 +1; delaysig_out5 <= '0'; end if; end if; end process; --X86 Chipset power managment Interface ############################# --This handles the powerbutton, as well as talks to the BMC and sequencer2 --Chain: BMC-->thisprocess-->chipset-->seq2-->VRMs --It does not support sleep states --BMC Software requires discipline: wait 1sec between turn off and turn on. process (reset_n, clk) begin if (reset_n='1') then delaysig_in2 <= '0'; all_onb <= '0'; x86_state <= (others => '0'); PCH_PWRBTN_N <= 'Z'; PGD_ALL_BMC <= '0'; else if (clk'event and clk = '1') then case ( x86_state ) is when "000" => --chipset standby s5 all_onb <= '0'; PGD_ALL_BMC <= '0'; if (PENA_ALL_BMC='1') then --BMC ordered power up x86_state <= "001"; delaysig_in2 <= '1'; --start 20ms delay PCH_PWRBTN_N <= '0'; --assert power button else delaysig_in2 <= '0'; PCH_PWRBTN_N <= 'Z'; end if; when "001" => --powerup powerbutton pressing if (delaysig_out2='1') then --button was pressed for 20ms x86_state <= "010"; delaysig_in2 <= '0'; PCH_PWRBTN_N <= 'Z'; --release it end if; when "010" => --powerup sequence if (PCH_SLPS3_N='1') then --chipset asserted SLP_S3 high all_onb <= '1'; --start the sequncer2 end if; if (all_pgoodb='1') then --sequncer2 completed up x86_state <= "011"; end if; when "011" => --chipset fully on PGD_ALL_BMC <= '1'; if (PENA_ALL_BMC='0') then --BMC turned off the power x86_state <= "100"; delaysig_in2 <= '1'; PCH_PWRBTN_N <= '0'; --assert power button end if; when "100" => --powerdown powerbutton pressing PGD_ALL_BMC <= '0'; if (delaysig_out2='1') then --button was pressed for 20ms x86_state <= "101"; delaysig_in2 <= '0'; PCH_PWRBTN_N <= 'Z'; --release it end if; when "101" => --powerdown sequence if (PCH_SLPS3_N='0') then --chipset asserted SLP_S3 low/off all_onb <= '0'; --start the sequncer2 down end if; if (all_pgoodb='0') then --sequncer2 completed down x86_state <= "000"; --go back to standby end if; when others => --error x86_state <= "000"; --go to state 0 all_onb <= '0'; end case; end if; end if; end process; --simple DELAY2: process ( reset_n, clk, delaysig_in2 ) begin if ( reset_n='0' or delaysig_in2='0') then delaysig_out2 <= '0'; delaycounter2 <= (others => '0'); elsif (clk'event and clk='1') then if ( delaycounter2 = "01111010000100100000" ) then --after 20msec (40ns clk period) delaysig_out2 <= '1'; delaycounter2 <= delaycounter2; --stop counting else delaycounter2 <= delaycounter2 +1; delaysig_out2 <= '0'; end if; end if; end process; -- RESETS AND OTHER STUFF ############################# PCH_RSTBTN_N1 <= BMC_TO_CPU_RST_N AND VCORECPU1_PG AND VCORECPU2_PG AND P1V0_PCH_S0_PG AND P3V3_S0_PG; process ( PCH_RSTBTN_N1 ) --3state buffer begin if (PCH_RSTBTN_N1='1') then PCH_RSTBTN_N <= 'Z'; else PCH_RSTBTN_N <= '0'; end if; end process; RST_SSD_N <= PLTRST_N AND P3V3_S0_PG AND P1V8_SSD_PG AND P1V2_SSD_PG; RST_PCIESLT1_N <= PLTRST_N AND P3V3_S0_PG; RST_PCIESLT2_N <= PLTRST_N AND P3V3_S0_PG; RST_PCIESLT3_N <= PLTRST_N AND P3V3_S0_PG; RST_PCIESLT4_N <= PLTRST_N AND P3V3_S0_PG; -- Other stuff: pseqstate_out(7 downto 4) <= pseqstate_outa; pseqstate_out(3 downto 0) <= pseqstate_outb; ALL_PWR_ON_LED_N <= NOT (all_pgooda AND all_pgoodb); PWRFAIL_LED_N <= NOT (pfailurea OR pfailureb); pfailure <= pfailurea OR pfailureb; --end file ---------------------------------------------------------------------- end Behavioral;