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
3 changes: 3 additions & 0 deletions BUILD.conf
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ environment('minibar', base = 'ecp5', contents = {
'--package CABGA554',
'--freq 50',
],
'nextpnr_ecp5_pack_flags': [
'--compress',
],
'nextpnr_constraints': ROOT + '/hdl/projects/minibar/minibar_controller.lpf',
})
environment('ignitionlet_sequencer', base = 'ignition_target', contents = {
Expand Down
2 changes: 2 additions & 0 deletions hdl/projects/minibar/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ bluespec_library('MinibarPcie',
deps = [
':MinibarRegsPkg',
'//hdl/ip/bsv:CommonFunctions',
'//hdl/ip/bsv:Countdown',
'//hdl/ip/bsv:Debouncer',
'//hdl/ip/bsv:PowerRail',
])

Expand Down
11 changes: 9 additions & 2 deletions hdl/projects/minibar/MinibarController.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,16 @@ module mkMinibarController#(Parameters parameters) (MinibarController);
Blinky#(50_000_000) blinky_inst <- Blinky::mkBlinky();

//
// Useful timer for the rest of the design
// Useful timers for the rest of the design
//
Strobe#(20) tick_1khz <-
mkLimitStrobe(1, parameters.system_frequency_hz / 1000, 0);
mkLimitStrobe(1, parameters.system_frequency_hz / 1_000, 0);
mkFreeRunningStrobe(tick_1khz);

Strobe#(6) tick_1mhz <-
mkLimitStrobe(1, (parameters.system_frequency_hz / 1_000_000), 0);
mkFreeRunningStrobe(tick_1mhz);

//
// A collection of miscellaneous registers we wrap up in a single module
//
Expand All @@ -72,6 +76,9 @@ module mkMinibarController#(Parameters parameters) (MinibarController);
// A block to support the operations and test sled<->CEM PCIe
//
MinibarPcie pcie_ <- mkMinibarPcie(parameters.pcie_pg_timeout_ms);
mkConnection(asIfc(tick_1khz), asIfc(pcie_.tick_1ms));
mkConnection(asIfc(tick_1mhz), asIfc(pcie_.tick_1us));
mkConnection(misc_regs.pcie_connector_present, pcie_.sled_present);

//
// Ignition Controllers
Expand Down
27 changes: 14 additions & 13 deletions hdl/projects/minibar/MinibarMiscRegs.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ interface MinibarMiscRegs;
method Action ignition_target0_present(Bool val);
method Action ignition_target1_present(Bool val);
interface PulseWire tick_1ms;
method Bool pcie_connector_present;
endinterface

module mkMinibarMiscRegs #(Integer pg_timeout_ms) (MinibarMiscRegs);
Reg#(Bool) tick <- mkDReg(False);
// Registers to wrap up and expose
Reg#(Bit#(1)) vbus_sys_fault_r <- mkReg(0);
Reg#(Bit#(3)) hcv_code_r <- mkReg(0);
Reg#(Bool) ignt_tgt0_present <- mkReg(False);
Reg#(Bool) ignt_tgt1_present <- mkReg(False);
Reg#(Bit#(1)) pcie_con_present <- mkReg(0);
Reg#(Bit#(1)) rsw0_con_present <- mkReg(0);
Reg#(Bit#(1)) rsw1_con_present <- mkReg(0);

// Lightly debounce these presence signals since we use them to drive logic in the PCIe block
Debouncer#(25, 25, Bit#(1)) pcie_con_present <- mkDebouncer(0);
Debouncer#(25, 25, Bit#(1)) rsw0_con_present <- mkDebouncer(0);
Debouncer#(25, 25, Bit#(1)) rsw1_con_present <- mkDebouncer(0);

// Software controllable registers
Reg#(PowerCtrl) power_control <- mkReg(defaultValue);
Expand All @@ -86,13 +88,6 @@ module mkMinibarMiscRegs #(Integer pg_timeout_ms) (MinibarMiscRegs);
Reg#(Bool) vbus_en_r <- mkReg(False);
Reg#(Bool) new_sw_vbus_en <- mkDReg(False);

(* fire_when_enabled *)
rule do_tick (tick);
vbus_rail.send();
power_button_short.send();
power_button_long.send();
endrule

(* fire_when_enabled *)
rule do_power_control;
let sw_enable = new_sw_vbus_en && power_control.vbus_sled_en == 1;
Expand All @@ -116,9 +111,13 @@ module mkMinibarMiscRegs #(Integer pg_timeout_ms) (MinibarMiscRegs);
method ignition_target1_present = ignt_tgt1_present._write;

interface PulseWire tick_1ms;
method _read = tick;
method Action send();
tick <= True;
vbus_rail.send();
power_button_short.send();
power_button_long.send();
pcie_con_present.send();
rsw0_con_present.send();
rsw1_con_present.send();
endmethod
endinterface

Expand Down Expand Up @@ -174,6 +173,8 @@ module mkMinibarMiscRegs #(Integer pg_timeout_ms) (MinibarMiscRegs);
});
endinterface

method pcie_connector_present = unpack(pcie_con_present);

endmodule

endpackage: MinibarMiscRegs
120 changes: 95 additions & 25 deletions hdl/projects/minibar/MinibarPcie.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
package MinibarPcie;

// BSV
import ConfigReg::*;
import DefaultValue::*;

// Oxide
import CommonFunctions::*;
import Countdown::*;
import Debouncer::*;
import PowerRail::*;

// Minibar
Expand All @@ -26,14 +29,14 @@ interface Pins;
method Bool refclk_buffer_bw_sel_oe;
method Bit#(1) refclk_buffer_bw_sel_o;
// Sled to FPGA interface
method Action sled_perst(Bit#(1) val);
method Bit#(1) sled_prsnt;
method Action sled_perst_l(Bit#(1) val);
method Bit#(1) sled_prsnt_l;
method Bit#(1) sled_attached;
method Bit#(1) sled_pwrflt;
method Bit#(1) sled_i2c_buffer_en;
// FPGA to CEM interface
method Bit#(1) cem_perst;
method Action cem_prsnt(Bit#(1) val);
method Bit#(1) cem_perst_l;
method Action cem_prsnt_l(Bit#(1) val);
method Bit#(1) cem_i2c_buffer_en;
// Power
interface PowerRail::Pins v12_pcie;
Expand All @@ -52,32 +55,46 @@ endinterface
interface MinibarPcie;
interface Pins pins;
interface Registers registers;
method Action tick_1ms(Bool val);
interface PulseWire tick_1ms;
interface PulseWire tick_1us;
method Action sled_present(Bool val);
endinterface

module mkMinibarPcie #(Integer pg_timeout_ms) (MinibarPcie);
Wire#(Bool) tick_1ms_ <- mkWire();

// Registers for input pins
Reg#(Bit#(1)) perst <- mkReg(0);
Reg#(Bit#(1)) prsnt <- mkReg(0);
// Wire from the PCIe connector presence register that we use for sled presence
Wire#(Bool) sled_present_ <- mkWire();

// Debounced prsnt_l input. The 25 ms debouncing on both rising and falling is arbitrary.
Debouncer#(25, 25, Bit#(1)) prsnt_l_in <- mkDebouncer(1);

// This represents the debounced PCIe PERST signal from the sled. This signal is driven by
// a buffer whose input comes from Gimlet. This signal will oscillate during
// Gimlet reboot and thus we should lightly debounce it. We've chosen to
// apply a 100us debounce to rising and falling edge as that is the minimum
// pulse width for Tperst per PCIe spec. The default state will
// be to assert reset (i.e. 0) until initial sampling has occurred.
Debouncer#(100, 100, Bit#(1)) sled_perst_l_in <- mkDebouncer(0);
Reg#(Bit#(1)) perst_l_out <- mkReg(0);
// We shouldn't assert PERST without making sure Tpvperl (100ms after power is stable) and
// Tperst-clk (100us after clocks are valid). We don't have a way of knowing what the status
// of the refclk is since it comes from the attached sled. We control power though, so we can
// enforce Tpvperl.
Countdown#(7) t_pvperl <- mkCountdownBy1();
ConfigReg#(Bool) t_pvperl_met <- mkConfigReg(False);

// Software controllable registers
Reg#(PciePowerCtrl) power_control <- mkReg(defaultValue);
Reg#(PcieRefclkCtrl) refclk_ctrl <- mkReg(defaultValue);
Reg#(PcieCtrl) pcie_ctrl <- mkReg(defaultValue);

// Power
PowerRail#(8) v12_rail <- mkPowerRailDisableOnAbort(pg_timeout_ms);
PowerRail#(8) v3p3_rail <- mkPowerRailDisableOnAbort(pg_timeout_ms);
// Register the enable state to work around some inellegance in the PowerRail module
Reg#(Bool) v12_en_r <- mkReg(False);
Reg#(Bool) v3p3_en_r <- mkReg(False);

(* fire_when_enabled *)
rule do_power_rail_ticks (tick_1ms_);
v12_rail.send();
v3p3_rail.send();
endrule
PulseWire tick_1ms_ <- mkPulseWire();

(* fire_when_enabled *)
rule do_power_control;
Expand All @@ -98,6 +115,41 @@ module mkMinibarPcie #(Integer pg_timeout_ms) (MinibarPcie);
end
endrule

(* fire_when_enabled *)
rule do_tpvperl(!t_pvperl_met);
if (v12_rail.enabled() && v3p3_rail.enabled()) begin
t_pvperl.send();
end else begin
t_pvperl <= fromInteger(100);
end
endrule

(* fire_when_enabled *)
rule do_tpvperl_reg;
if (!v12_rail.enabled() || !v3p3_rail.enabled()) begin
t_pvperl_met <= False;
end else if (!t_pvperl_met) begin
t_pvperl_met <= t_pvperl;
end
endrule

// There are a couple layers of PERST control between an attached sled and the PCIe slot.
// First, if a sled is not present, we just assert PERST. This is because the refclk comes from
// the sled, so without a sled there's no reason for the PCIe device to be out of reset. We also
// assert PERST until t_pvperl timing has been met.
// Next, we check if the bits have been set to provide control of PERST to software.
// Finally, we just pass through the debounced PERST signal from the sled.
(* fire_when_enabled *)
rule do_perst;
if (!sled_present_ || !t_pvperl_met) begin
perst_l_out <= 0;
end else if (pcie_ctrl.fpga_perst_override == 1) begin
perst_l_out <= pcie_ctrl.fpga_perst_control;
end else begin
perst_l_out <= sled_perst_l_in;
end
endrule

//
// PCIe Refclk Buffer Bandwidth selection
// See PLL Operating Mode Select Table of PI6CB33201 datasheet
Expand Down Expand Up @@ -129,19 +181,17 @@ module mkMinibarPcie #(Integer pg_timeout_ms) (MinibarPcie);
endcase
endrule

method tick_1ms = tick_1ms_._write;

interface Pins pins;
method refclk_buffer_oe0 = refclk_ctrl.oe0;
method refclk_buffer_oe1 = refclk_ctrl.oe1;
method refclk_buffer_pd = refclk_ctrl.pd;
method refclk_buffer_bw_sel_o = refclk_bw_sel_o;
method refclk_buffer_bw_sel_oe = refclk_bw_sel_oe;
method sled_perst = perst._write;
method sled_prsnt = prsnt;
method sled_perst_l = sled_perst_l_in._write;
method sled_prsnt_l = prsnt_l_in;
method sled_pwrflt = pcie_ctrl.sled_pwrflt;
method cem_perst = perst;
method cem_prsnt = prsnt._write;
method cem_perst_l = perst_l_out;
method cem_prsnt_l = prsnt_l_in._write;
method sled_attached = pcie_ctrl.attached;
method sled_i2c_buffer_en = pcie_ctrl.sled_i2c_en;
method cem_i2c_buffer_en = pcie_ctrl.cem_i2c_en;
Expand Down Expand Up @@ -169,12 +219,32 @@ module mkMinibarPcie #(Integer pg_timeout_ms) (MinibarPcie);
interface pcie_ctrl = pcie_ctrl;
interface pcie_rdbk = valueToReadOnly(
PcieRdbk {
cem_prsnt: prsnt,
cem_perst: perst,
sled_prsnt: prsnt,
sled_perst: perst
sled_con: pack(sled_present_),
cem_prsnt_l: prsnt_l_in,
cem_perst_l: perst_l_out,
sled_prsnt_l: prsnt_l_in,
sled_perst_l: sled_perst_l_in
});
endinterface

interface PulseWire tick_1ms;
method _read = False;
method Action send;
tick_1ms_.send();
v12_rail.send();
v3p3_rail.send();
prsnt_l_in.send();
endmethod
endinterface

interface PulseWire tick_1us;
method _read = False;
method Action send;
sled_perst_l_in.send();
endmethod
endinterface

method sled_present = sled_present_._write;
endmodule

endpackage: MinibarPcie
18 changes: 9 additions & 9 deletions hdl/projects/minibar/MinibarTop.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -187,15 +187,15 @@ module mkMinibarTop(MinibarTop);
ReadOnly#(Bool) v3p3_en <- mkOutputSyncFor(controller.pcie.v3p3_pcie.en);
InputReg#(Bool, 2) v3p3_pg <- mkInputSyncFor(controller.pcie.v3p3_pcie.pg);
// Sled to FPGA
InputReg#(Bit#(1), 2) sled_perst <- mkInputSyncFor(controller.pcie.sled_perst);
ReadOnly#(Bit#(1)) sled_prsnt <- mkOutputSyncFor(controller.pcie.sled_prsnt);
InputReg#(Bit#(1), 2) sled_perst_l <- mkInputSyncFor(controller.pcie.sled_perst_l);
ReadOnly#(Bit#(1)) sled_prsnt_l <- mkOutputSyncFor(controller.pcie.sled_prsnt_l);
ReadOnly#(Bit#(1)) sled_attached <- mkOutputSyncFor(controller.pcie.sled_attached);
ReadOnly#(Bit#(1)) sled_pwrflt <- mkOutputSyncFor(controller.pcie.sled_pwrflt);
ReadOnly#(Bit#(1)) sled_i2c_en <- mkOutputSyncFor(controller.pcie.sled_i2c_buffer_en);
// FPGA to CEM
ReadOnly#(Bit#(1)) cem_perst <- mkOutputSyncFor(controller.pcie.cem_perst);
InputReg#(Bit#(1), 2) cem_prsnt <- mkInputSyncFor(controller.pcie.cem_prsnt);
ReadOnly#(Bit#(1)) cem_i2c_en <- mkOutputSyncFor(controller.pcie.cem_i2c_buffer_en);
ReadOnly#(Bit#(1)) cem_perst_l <- mkOutputSyncFor(controller.pcie.cem_perst_l);
InputReg#(Bit#(1), 2) cem_prsnt_l <- mkInputSyncFor(controller.pcie.cem_prsnt_l);
ReadOnly#(Bit#(1)) cem_i2c_en <- mkOutputSyncFor(controller.pcie.cem_i2c_buffer_en);
// Refclk
ReadOnly#(Bit#(1)) pcie_refclk_oe0 <- mkOutputSyncFor(controller.pcie.refclk_buffer_oe0);
ReadOnly#(Bit#(1)) pcie_refclk_oe1 <- mkOutputSyncFor(controller.pcie.refclk_buffer_oe1);
Expand Down Expand Up @@ -293,15 +293,15 @@ module mkMinibarTop(MinibarTop);

// PCIe
// Sled to FPGA
method pcie_aux_sled_to_fpga_perst_l = sync_inverted(sled_perst);
method pcie_aux_sled_to_fpga_perst_l = sync(sled_perst_l);
method fpga_to_pcie_sled_i2c_buffer_en = sled_i2c_en;
method fpga_to_sled_pcie_attached_l = ~sled_attached;
method pcie_aux_fpga_to_sled_pwrflt_l = ~sled_pwrflt;
method pcie_aux_fpga_to_sled_prsnt_l = ~sled_prsnt;
method pcie_aux_fpga_to_sled_prsnt_l = sled_prsnt_l;
// FPGA to CEM
method pcie_aux_cem_to_fpga_prsnt_l = sync_inverted(cem_prsnt);
method pcie_aux_cem_to_fpga_prsnt_l = sync(cem_prsnt_l);
method fpga_to_pcie_cem_i2c_buffer_en = ~cem_i2c_en;
method pcie_aux_fpga_to_cem_perst_l = ~cem_perst;
method pcie_aux_fpga_to_cem_perst_l = cem_perst_l;
// Refclk
method fpga_to_pcie_aux_refclk_buffer_oe0_l = ~pcie_refclk_oe0;
method fpga_to_pcie_aux_refclk_buffer_oe1_l = ~pcie_refclk_oe1;
Expand Down
Loading