Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions hdl/ip/vhd/irq/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("//tools:hdl.bzl", "vhdl_unit", "vunit_sim")


vhdl_unit(
name = "irq_block",
srcs = ["irq_block.vhd"],
deps = [],
visibility = ['PUBLIC'],
)
88 changes: 88 additions & 0 deletions hdl/ip/vhd/irq/irq_block.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
--
-- Copyright 2026 Oxide Computer Company

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity irq_block is
generic (
IRQ_OUT_ACTIVE_HIGH : boolean;
NUM_IRQS : natural
);
port (
clk : in std_logic;
reset : in std_logic;
-- raw IRQ, can be level or edge sensitive.
-- if level, upstack code will need to clear the driving bit to prevent repeated interrupts.
-- and just clearing the flag here will not be sufficient.
irq_in : in std_logic_vector(NUM_IRQS - 1 downto 0);
irq_en : in std_logic_vector(NUM_IRQS - 1 downto 0);
level_edge_n : in std_logic_vector(NUM_IRQS - 1 downto 0); -- 1 for level sensitive, 0 for edge sensitive
irq_out : out std_logic_vector(NUM_IRQS - 1 downto 0);
irq_clear : in std_logic_vector(NUM_IRQS - 1 downto 0);
irq_force : in std_logic_vector(NUM_IRQS - 1 downto 0);
irq_pin : out std_logic

);
end entity;

architecture rtl of irq_block is
constant IS_EDGE_SENSITIVE : std_logic := '0';
constant IS_LEVEL_SENSITIVE : std_logic := '1';
signal irq_in_last : std_logic_vector(irq_in'range);
signal irq_reg : std_logic_vector(irq_in'range);

begin


-- Register/latch the incoming IRQs.

process(clk, reset)
variable irq_redge : std_logic_vector(irq_in'range);
variable irq_pin_int : std_logic;
begin
if reset then
irq_out <= (others => '0');
irq_reg <= (others => '0');
irq_in_last <= (others => '0');
irq_pin <= '0';
elsif rising_edge(clk) then
irq_redge := (irq_in and not irq_in_last);
irq_in_last <= irq_in; -- this will support edge detection for edge sensitive IRQs.

-- We need to properly handle the case where we're clearing the IRQ and
-- it is set the
for i in irq_in'range loop
-- Deal with rising edge or force first. These take precedence over any
-- clearing of the IRQ so we don't miss one.
if irq_redge(i) or irq_force(i) then
irq_reg(i) <= '1';
elsif irq_clear(i) then
irq_reg(i) <= '0';
end if;

-- now deal with level vs edge sensitivity. If it's level sensitive, then we just need to mirror the input
if level_edge_n(i) = IS_EDGE_SENSITIVE then
irq_out(i) <= irq_reg(i);
else
irq_out(i) <= irq_in(i);
end if;
end loop;

-- make the output pin registered since it could go chip-external
-- this is an OR reduction
irq_pin_int := or (irq_out and irq_en);
if IRQ_OUT_ACTIVE_HIGH then
irq_pin <= irq_pin_int;
else
irq_pin <= not irq_pin_int;
end if;

end if;
end process;

end architecture;
2 changes: 1 addition & 1 deletion hdl/projects/cosmo_seq/cosmo_seq_top.rdl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ addrmap pca9506_axi_regs {
};
addrmap cosmo_seq_top {
default regwidth = 32;
// Instantiate 2 to test nesting

info_regs info @ 0x0;
spi_nor_regs spi_nor @ 0x0100;
sequencer_regs sequencer @ 0x0200;
Expand Down
3 changes: 3 additions & 0 deletions hdl/projects/cosmo_seq/cosmo_seq_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ architecture rtl of cosmo_seq_top is

signal sp5_t6_power_en : std_logic;
signal sp5_t6_perst_l : std_logic;
signal sp5_t6_faulted : std_logic;
signal espi_resp_csn : std_logic;
signal hp_int_n : std_logic;

Expand Down Expand Up @@ -684,6 +685,7 @@ begin
pcie_clk_buff_m2b_oe_l => fpga1_to_pcie_clk_buff_m2b_oe_l,
t6_power_en => sp5_t6_power_en,
t6_perst_l => sp5_t6_perst_l,
t6_faulted => sp5_t6_faulted,
pcie_aux_rsw_perst_l => pcie_aux_fpga1_to_rsw_perst_l,
pcie_aux_rsw_prsnt_buff_l => pcie_aux_rsw_to_fpga1_prsnt_buff_l,
pcie_aux_rsw_pwrflt_buff_l=> pcie_aux_rsw_to_fpga1_pwrflt_buff_l,
Expand Down Expand Up @@ -728,6 +730,7 @@ begin
nic_seq_pins => nic_seq_pins,
nic_dbg_pins => nic_dbg_pins,
sp5_t6_perst_l => sp5_t6_perst_l,
sp5_t6_faulted => sp5_t6_faulted,
ignition_mux_sel => fpga1_to_sp_mux_ign_mux_sel,
ignition_creset => fpga1_to_ign_trgt_fpga_creset,
reg_alert_l_pins => reg_alert_l_pins
Expand Down
1 change: 1 addition & 0 deletions hdl/projects/cosmo_seq/sequencer/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ vhdl_unit(
deps = [
":sequencer_regs_rdl",
"//hdl/ip/vhd/synchronizers:meta_sync",
"//hdl/ip/vhd/irq:irq_block",
"//hdl/ip/vhd/axi_blocks:axilite_if_2k19",
],
visibility = ["PUBLIC"],
Expand Down
28 changes: 2 additions & 26 deletions hdl/projects/cosmo_seq/sequencer/a1_a0_seq.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,8 @@ architecture rtl of a1_a0_seq is
constant SIX_HUNDRED_MS: integer := 600 * ONE_MS;
constant SIX_TWENTY_MS: integer := 620 * ONE_MS;
constant ONE_SECOND: integer := 1000 * ONE_MS;


-- This is going into a "RAW" register,
-- exposed to hubris. Changes here may impact
-- debugging tools. Should we push this to
-- the rdl? It makes maintenance here more annoying.
type seq_state_t is (
IDLE,
DDR_BULK_EN,
GROUP_A_EN,
GROUP_A_PG_AND_WAIT,
RSM_RST_DEASSERT,
RTC_CLK_WAIT, -- PBTN low for 20ms
SLP_CHECKPOINT,
GROUP_B_EN,
GROUP_B_PG_AND_WAIT,
GROUP_C_EN, -- Maybe???
GROUP_C_PG_AND_WAIT,
ASSERT_PWRGOOD,
WAIT_PWROK,
WAIT_RESET_L_RELEASE,
DONE,
SAFE_DISABLE
);
type seq_r_t is record
state : seq_state_t;
state : seq_raw_status_hw_sm;
enable_pend: std_logic;
enable_last: std_logic;
cnts : unsigned(31 downto 0);
Expand Down Expand Up @@ -171,7 +147,7 @@ begin
end process;

-- Decode state into a number representing position in the enum type
raw_state.hw_sm <= std_logic_vector(to_unsigned(seq_state_t'pos(seq_r.state), raw_state.hw_sm'length));
raw_state.hw_sm <= seq_r.state;


seq_ns_logic: process(all)
Expand Down
20 changes: 12 additions & 8 deletions hdl/projects/cosmo_seq/sequencer/nic_seq.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ architecture rtl of nic_seq is
constant TWENTY_MS : integer := 20 * ONE_MS;
constant THIRTY_MS : integer := 30 * ONE_MS;

type state_t is ( IDLE, PWR_EN, WAIT_FOR_PGS, EARLY_CLD_RST, EARLY_PERST, EARLY_PERST_ASSERT, DONE );

type reset_state_t is (IN_RESET, CLD_RST_DEASSERTED, PERST_DEASSERTED);
type rst_r_t is record
state : reset_state_t;
Expand All @@ -68,10 +66,11 @@ architecture rtl of nic_seq is
);

type nic_r_t is record
state : state_t;
state : nic_raw_status_hw_sm;
enable_last : std_logic;
enable_pend : std_logic;
cnts : unsigned(31 downto 0);
nic_perst_l_last : std_logic;
nic_power_en : std_logic;
nic_perst_l : std_logic;
nic_cld_rst_l : std_logic;
Expand All @@ -85,6 +84,7 @@ architecture rtl of nic_seq is
enable_last => '0',
enable_pend => '0',
cnts => (others => '0'),
nic_perst_l_last => '0',
nic_power_en => '0',
nic_perst_l => '0',
nic_cld_rst_l => '0',
Expand All @@ -100,7 +100,7 @@ architecture rtl of nic_seq is

begin

raw_state.hw_sm <= std_logic_vector(to_unsigned(state_t'pos(nic_r.state), raw_state.hw_sm'length));
raw_state.hw_sm <= nic_r.state;

nic_idle <= '1' when nic_r.state = IDLE else '0';

Expand Down Expand Up @@ -160,13 +160,17 @@ begin
begin

v := nic_r;
v.nic_perst_l_last := sp5_t6_perst_l;


-- Fault monitoring: if we expect NIC rails to be up and they're not, that's a fault
nic_faulted_var := '1' when nic_r.nic_expected = '1' and (not is_power_good(nic_rails)) else '0';
v.enable_last := sw_enable;
if sw_enable and not nic_r.enable_last then
-- To re-enable, we require software to generate a rising_edge
-- here, by clearing the enable and then setting it again
if (sw_enable and not nic_r.enable_last) = '1' or (nic_r.faulted = '1' and nic_r.nic_perst_l_last = '0' and sp5_t6_perst_l = '1') then
-- To re-enable, there are 2 possible cases:
-- Normally, we require sw to clear and enable the register for normal power up cases.
-- In a MAPO situation though, the SP5 has "power control". sp5_t6_perst_l just followes the slot power
-- enable here, so if we have MAPO'd (faulted = '1') and we see a perst de-assert from the SP5, we'll attempt to sequence again.
v.enable_pend := '1';
-- we'll use this to clear the faulted flags
v.faulted := '0';
Expand Down Expand Up @@ -251,7 +255,7 @@ begin

-- MAPO fault handling - monitored in all non-IDLE states
if nic_r.state /= IDLE then
if nic_faulted_var = '1' or upstream_ok = '0' then
if nic_faulted_var = '1' or upstream_ok = '0' or nic_overrides_reg.nic_test_mapo = '1' then
v.faulted := '1';
-- In fault case, immediately transition to IDLE
-- regardless of current state
Expand Down
43 changes: 40 additions & 3 deletions hdl/projects/cosmo_seq/sequencer/sequencer_regs.rdl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ addrmap sequencer_regs {
desc = "A1A0 MAPO- A fault in the A1-A0 domain(s) caused a MAPO (sticky since fpga reset or last clear)";
} a0mapo[1];
field {
desc = "Nic MAPO- A fault in the A0 domain caused a MAPO (sticky since fpga reset or last clear)";
desc = "Nic MAPO- A fault in the NIC domain caused a MAPO (sticky since fpga reset or last clear)";
} nicmapo[1];
field {
desc = "AMD PWROK falling edge while in >=A0 (sticky since fpga reset or last clear)";
Expand Down Expand Up @@ -91,9 +91,13 @@ This regulator controls V1P1_SP5_A0, V1P8_SP5_A0 and V3P3_SP5_A0 rails.";
};
// Set up interrupt registers using a common irq_type
irq IFR;
IFR->name = "Interrupt Flag Register";
IFR->name = "Interrupt Flag Register (W1C)";
irq IER;
IER->name = "Interrupt Enable Register";
irq IGR;
IGR->name = "Interrupt Generate Register self-clearing (W1S)";
irq ILR;
ILR->name = "Interrupt Live Register (read-only). Current 'raw' inputs to the IRQ block";

reg {
name = "Sequencer Status Register";
Expand Down Expand Up @@ -197,8 +201,28 @@ This regulator controls V1P1_SP5_A0, V1P8_SP5_A0 and V3P3_SP5_A0 rails.";
your friendly hw engineer for a true decode if needed.";
default sw = r;

enum a0_hw_state_machine {
IDLE = 8'h00 {desc = "";};
DDR_BULK_EN = 8'h01 {desc = "";};
GROUP_A_EN = 8'h02 {desc = "";};
GROUP_A_PG_AND_WAIT = 8'h03 {desc = "";};
RSM_RST_DEASSERT = 8'h04 {desc = "";};
RTC_CLK_WAIT = 8'h05 {desc = "";}; // PBTN low for 20ms
SLP_CHECKPOINT = 8'h06 {desc = "";};
GROUP_B_EN = 8'h07 {desc = "";};
GROUP_B_PG_AND_WAIT = 8'h08 {desc = "";};
GROUP_C_EN = 8'h09 {desc = "";};
GROUP_C_PG_AND_WAIT = 8'h0a {desc = "";};
ASSERT_PWRGOOD = 8'h0b {desc = "";};
WAIT_PWROK = 8'h0c {desc = "";};
WAIT_RESET_L_RELEASE = 8'h0d {desc = "";};
DONE = 8'h0e {desc = "";};
SAFE_DISABLE = 8'h0f {desc = "";};
};

field {
desc = "Sequencer Raw Status";
encode = a0_hw_state_machine;
} hw_sm[7:0];
} seq_raw_status;

Expand All @@ -220,7 +244,6 @@ This regulator controls V1P1_SP5_A0, V1P8_SP5_A0 and V3P3_SP5_A0 rails.";
desc = "Nic SM Status";
encode = nic_state_machine;
} nic_sm[7:0];
// TODO: A1 state machine decode in here
} nic_api_status;

reg {
Expand All @@ -231,8 +254,19 @@ This regulator controls V1P1_SP5_A0, V1P8_SP5_A0 and V3P3_SP5_A0 rails.";
your friendly hw engineer for a true decode if needed.";
default sw = r;

enum nic_hw_state_machine {
IDLE = 8'h00 {desc = "";};
PWR_EN = 8'h01 {desc = "";};
WAIT_FOR_PGS = 8'h02 {desc = "";};
EARLY_CLD_RST = 8'h03 {desc = "";};
EARLY_PERST = 8'h04 {desc = "";};
EARLY_PERST_ASSERT = 8'h05 {desc = "";};
DONE = 8'h06 {desc = "";};
};

field {
desc = "NIC Sequencer Raw Status";
encode = nic_hw_state_machine;
} hw_sm[7:0];
} nic_raw_status;

Expand Down Expand Up @@ -451,6 +485,9 @@ This regulator controls V1P1_SP5_A0, V1P8_SP5_A0 and V3P3_SP5_A0 rails.";
field {
desc = "nic_pcie_clk_buff_oe_l live status, note: only valid when SP5 rails are up (From FPGA to buffer)";
} nic_pcie_clk_buff_oe_l[1] = 1;
field {
desc = "Self-clearing. Set to 1 to trigger a NIC-domain MAPO for testing purposes.";
} nic_test_mapo[1] = 1;
} nic_overrides;

reg {
Expand Down
Loading