[clkmgr] Add clock-gated indication signals This adds "clock gated" indication output signals that are encoded using the `lc_tx_t`. These signals will be wired over to the alert handler in a subsequent PR in order to connect them to the alert low-power groups (LPGs). Note that these signals will be passed through 2-stage synchronizers on the alert handler side. The timing of these signals does not have to be cycle accurate. Note, this is dependent on #8417 (first commit will disappear). Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/hw/ip/clkmgr/data/clkmgr.hjson.tpl b/hw/ip/clkmgr/data/clkmgr.hjson.tpl index f75e6d0..7ce0f55 100644 --- a/hw/ip/clkmgr/data/clkmgr.hjson.tpl +++ b/hw/ip/clkmgr/data/clkmgr.hjson.tpl
@@ -49,6 +49,13 @@ package: "clkmgr_pkg", }, + { struct: "clkmgr_cg_en", + type: "uni", + name: "cg_en", + act: "req", + package: "clkmgr_pkg", + }, + { struct: "lc_tx", type: "uni", name: "lc_dft_en",
diff --git a/hw/ip/clkmgr/data/clkmgr.sv.tpl b/hw/ip/clkmgr/data/clkmgr.sv.tpl index f4601d8..30ebb24 100644 --- a/hw/ip/clkmgr/data/clkmgr.sv.tpl +++ b/hw/ip/clkmgr/data/clkmgr.sv.tpl
@@ -61,6 +61,9 @@ // jittery enable output logic jitter_en_o, + // clock gated indications going to alert handlers + output clkmgr_cg_en_t cg_en_o, + // clock output interface % for intf in cfg['exported_clks']: output clkmgr_${intf}_out_t clocks_${intf}_o, @@ -189,6 +192,9 @@ .clk_i(clk_${v.src.name}_i), .clk_o(clocks_o.${k}) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.${k} = lc_ctrl_pkg::Off; % endfor //////////////////////////////////////////////////// @@ -332,6 +338,14 @@ //////////////////////////////////////////////////// % for k,v in typed_clocks.rg_clks.items(): assign clocks_o.${k} = clk_${v.src.name}_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_${k} ( + .clk_i(clk_${v.src.name}_i), + .rst_ni(rst_${v.src.name}_ni), + .lc_en_i(((clk_${v.src.name}_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.${k}) + ); % endfor //////////////////////////////////////////////////// @@ -363,15 +377,27 @@ .lc_en_o(${k}_scanmode) ); + logic ${k}_combined_en; + assign ${k}_combined_en = ${k}_sw_en & clk_${v.src.name}_en; prim_clock_gating #( .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions. ) u_${k}_cg ( .clk_i(clk_${v.src.name}_root), - .en_i(${k}_sw_en & clk_${v.src.name}_en), + .en_i(${k}_combined_en), .test_en_i(${k}_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.${k}) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_${k} ( + .clk_i(clk_${v.src.name}_i), + .rst_ni(rst_${v.src.name}_ni), + .lc_en_i(((${k}_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.${k}) + ); + % endfor //////////////////////////////////////////////////// @@ -408,15 +434,33 @@ .lc_en_o(${clk}_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic ${clk}_combined_en; + prim_buf u_prim_buf_${clk}_en ( + .in_i(${clk}_en & clk_${sig.src.name}_en), + .out_o(${clk}_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_${clk}_cg ( .clk_i(clk_${sig.src.name}_root), - .en_i(${clk}_en & clk_${sig.src.name}_en), + .en_i(${clk}_combined_en), .test_en_i(${clk}_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.${clk}) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_${clk} ( + .clk_i(clk_${sig.src.name}_i), + .rst_ni(rst_${sig.src.name}_ni), + .lc_en_i(((${clk}_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.${clk}) + ); + % endfor // state readback @@ -454,5 +498,6 @@ `ASSERT_KNOWN(ExportClocksKownO_A, clocks_${intf}_o) % endfor `ASSERT_KNOWN(ClocksKownO_A, clocks_o) + `ASSERT_KNOWN(CgEnKnownO_A, cg_en_o) endmodule // clkmgr
diff --git a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl index 84c569b..21e74e8 100644 --- a/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl +++ b/hw/ip/clkmgr/data/clkmgr_pkg.sv.tpl
@@ -14,13 +14,23 @@ % endfor } hint_names_e; + // clocks generated and broadcast typedef struct packed { % for clk in typed_clocks.all_clocks(): logic ${clk}; % endfor - } clkmgr_out_t; + // clock gating indication for alert handler + typedef struct packed { +<% n_clk = 0 %>\ +% for clk in typed_clocks.all_clocks(): + lc_ctrl_pkg::lc_tx_t ${clk};<% n_clk += 1 %> +% endfor + } clkmgr_cg_en_t; + + parameter int NumOutputClk = ${n_clk}; + % for intf, eps in cfg['exported_clks'].items(): typedef struct packed { % for ep, clks in eps.items():
diff --git a/hw/ip/clkmgr/dv/tb.sv b/hw/ip/clkmgr/dv/tb.sv index c08dd7b..2d05d58 100644 --- a/hw/ip/clkmgr/dv/tb.sv +++ b/hw/ip/clkmgr/dv/tb.sv
@@ -105,6 +105,8 @@ .lc_clk_byp_req_i (clkmgr_if.lc_clk_byp_req), .lc_clk_byp_ack_o (clkmgr_if.lc_clk_byp_ack), + .cg_en_o ( ), + .jitter_en_o(clkmgr_if.jitter_en_o), .clocks_o (clkmgr_if.clocks_o) );
diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson index 364488a..6992eca 100644 --- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson +++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
@@ -2839,6 +2839,16 @@ index: -1 } { + name: cg_en + struct: clkmgr_cg_en + package: clkmgr_pkg + type: uni + act: req + width: 1 + inst_name: clkmgr_aon + index: -1 + } + { name: lc_dft_en struct: lc_tx package: lc_ctrl_pkg @@ -14919,6 +14929,16 @@ index: -1 } { + name: cg_en + struct: clkmgr_cg_en + package: clkmgr_pkg + type: uni + act: req + width: 1 + inst_name: clkmgr_aon + index: -1 + } + { name: lc_dft_en struct: lc_tx package: lc_ctrl_pkg
diff --git a/hw/top_earlgrey/ip/clkmgr/clkmgr.core b/hw/top_earlgrey/ip/clkmgr/clkmgr.core index 74f8842..211fcd5 100644 --- a/hw/top_earlgrey/ip/clkmgr/clkmgr.core +++ b/hw/top_earlgrey/ip/clkmgr/clkmgr.core
@@ -12,6 +12,7 @@ - lowrisc:ip:pwrmgr_pkg - lowrisc:ip:tlul - lowrisc:prim:all + - lowrisc:prim:buf - lowrisc:prim:clock_buf - lowrisc:prim:clock_div - lowrisc:prim:clock_gating
diff --git a/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson b/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson index 6d02c08..d61d868 100644 --- a/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson +++ b/hw/top_earlgrey/ip/clkmgr/data/autogen/clkmgr.hjson
@@ -55,6 +55,13 @@ package: "clkmgr_pkg", }, + { struct: "clkmgr_cg_en", + type: "uni", + name: "cg_en", + act: "req", + package: "clkmgr_pkg", + }, + { struct: "lc_tx", type: "uni", name: "lc_dft_en",
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv index 0d09f1d..d906e94 100644 --- a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv +++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv
@@ -70,6 +70,9 @@ // jittery enable output logic jitter_en_o, + // clock gated indications going to alert handlers + output clkmgr_cg_en_t cg_en_o, + // clock output interface output clkmgr_out_t clocks_o @@ -213,43 +216,73 @@ .clk_i(clk_io_div4_i), .clk_o(clocks_o.clk_io_div4_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_io_div4_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_aon_powerup_buf ( .clk_i(clk_aon_i), .clk_o(clocks_o.clk_aon_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_aon_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_main_powerup_buf ( .clk_i(clk_main_i), .clk_o(clocks_o.clk_main_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_main_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_io_powerup_buf ( .clk_i(clk_io_i), .clk_o(clocks_o.clk_io_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_io_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_usb_powerup_buf ( .clk_i(clk_usb_i), .clk_o(clocks_o.clk_usb_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_usb_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_io_div2_powerup_buf ( .clk_i(clk_io_div2_i), .clk_o(clocks_o.clk_io_div2_powerup) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_io_div2_powerup = lc_ctrl_pkg::Off; prim_clock_buf u_clk_aon_infra_buf ( .clk_i(clk_aon_i), .clk_o(clocks_o.clk_aon_infra) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_aon_infra = lc_ctrl_pkg::Off; prim_clock_buf u_clk_aon_secure_buf ( .clk_i(clk_aon_i), .clk_o(clocks_o.clk_aon_secure) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_aon_secure = lc_ctrl_pkg::Off; prim_clock_buf u_clk_aon_peri_buf ( .clk_i(clk_aon_i), .clk_o(clocks_o.clk_aon_peri) ); + + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_aon_peri = lc_ctrl_pkg::Off; prim_clock_buf u_clk_aon_timers_buf ( .clk_i(clk_aon_i), .clk_o(clocks_o.clk_aon_timers) ); + // clock gated indication for alert handler: these clocks are never gated. + assign cg_en_o.clk_aon_timers = lc_ctrl_pkg::Off; + //////////////////////////////////////////////////// // Root gating //////////////////////////////////////////////////// @@ -559,12 +592,60 @@ // Clocks with only root gate //////////////////////////////////////////////////// assign clocks_o.clk_io_div4_infra = clk_io_div4_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_io_div4_infra ( + .clk_i(clk_io_div4_i), + .rst_ni(rst_io_div4_ni), + .lc_en_i(((clk_io_div4_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div4_infra) + ); assign clocks_o.clk_main_infra = clk_main_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_main_infra ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_infra) + ); assign clocks_o.clk_io_div4_secure = clk_io_div4_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_io_div4_secure ( + .clk_i(clk_io_div4_i), + .rst_ni(rst_io_div4_ni), + .lc_en_i(((clk_io_div4_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div4_secure) + ); assign clocks_o.clk_main_secure = clk_main_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_main_secure ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_secure) + ); assign clocks_o.clk_usb_secure = clk_usb_root; + + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_usb_secure ( + .clk_i(clk_usb_i), + .rst_ni(rst_usb_ni), + .lc_en_i(((clk_usb_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_usb_secure) + ); assign clocks_o.clk_io_div4_timers = clk_io_div4_root; + // clock gated indication for alert handler + prim_lc_sender u_prim_lc_sender_clk_io_div4_timers ( + .clk_i(clk_io_div4_i), + .rst_ni(rst_io_div4_ni), + .lc_en_i(((clk_io_div4_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div4_timers) + ); + //////////////////////////////////////////////////// // Software direct control group //////////////////////////////////////////////////// @@ -594,15 +675,27 @@ .lc_en_o(clk_io_div4_peri_scanmode) ); + logic clk_io_div4_peri_combined_en; + assign clk_io_div4_peri_combined_en = clk_io_div4_peri_sw_en & clk_io_div4_en; prim_clock_gating #( .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions. ) u_clk_io_div4_peri_cg ( .clk_i(clk_io_div4_root), - .en_i(clk_io_div4_peri_sw_en & clk_io_div4_en), + .en_i(clk_io_div4_peri_combined_en), .test_en_i(clk_io_div4_peri_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_io_div4_peri) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_io_div4_peri ( + .clk_i(clk_io_div4_i), + .rst_ni(rst_io_div4_ni), + .lc_en_i(((clk_io_div4_peri_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div4_peri) + ); + prim_flop_2sync #( .Width(1) ) u_clk_io_div2_peri_sw_en_sync ( @@ -623,15 +716,27 @@ .lc_en_o(clk_io_div2_peri_scanmode) ); + logic clk_io_div2_peri_combined_en; + assign clk_io_div2_peri_combined_en = clk_io_div2_peri_sw_en & clk_io_div2_en; prim_clock_gating #( .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions. ) u_clk_io_div2_peri_cg ( .clk_i(clk_io_div2_root), - .en_i(clk_io_div2_peri_sw_en & clk_io_div2_en), + .en_i(clk_io_div2_peri_combined_en), .test_en_i(clk_io_div2_peri_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_io_div2_peri) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_io_div2_peri ( + .clk_i(clk_io_div2_i), + .rst_ni(rst_io_div2_ni), + .lc_en_i(((clk_io_div2_peri_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div2_peri) + ); + prim_flop_2sync #( .Width(1) ) u_clk_io_peri_sw_en_sync ( @@ -652,15 +757,27 @@ .lc_en_o(clk_io_peri_scanmode) ); + logic clk_io_peri_combined_en; + assign clk_io_peri_combined_en = clk_io_peri_sw_en & clk_io_en; prim_clock_gating #( .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions. ) u_clk_io_peri_cg ( .clk_i(clk_io_root), - .en_i(clk_io_peri_sw_en & clk_io_en), + .en_i(clk_io_peri_combined_en), .test_en_i(clk_io_peri_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_io_peri) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_io_peri ( + .clk_i(clk_io_i), + .rst_ni(rst_io_ni), + .lc_en_i(((clk_io_peri_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_peri) + ); + prim_flop_2sync #( .Width(1) ) u_clk_usb_peri_sw_en_sync ( @@ -681,15 +798,27 @@ .lc_en_o(clk_usb_peri_scanmode) ); + logic clk_usb_peri_combined_en; + assign clk_usb_peri_combined_en = clk_usb_peri_sw_en & clk_usb_en; prim_clock_gating #( .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions. ) u_clk_usb_peri_cg ( .clk_i(clk_usb_root), - .en_i(clk_usb_peri_sw_en & clk_usb_en), + .en_i(clk_usb_peri_combined_en), .test_en_i(clk_usb_peri_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_usb_peri) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_usb_peri ( + .clk_i(clk_usb_i), + .rst_ni(rst_usb_ni), + .lc_en_i(((clk_usb_peri_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_usb_peri) + ); + //////////////////////////////////////////////////// // Software hint group @@ -730,15 +859,33 @@ .lc_en_o(clk_main_aes_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic clk_main_aes_combined_en; + prim_buf u_prim_buf_clk_main_aes_en ( + .in_i(clk_main_aes_en & clk_main_en), + .out_o(clk_main_aes_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_clk_main_aes_cg ( .clk_i(clk_main_root), - .en_i(clk_main_aes_en & clk_main_en), + .en_i(clk_main_aes_combined_en), .test_en_i(clk_main_aes_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_main_aes) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_main_aes ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_aes_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_aes) + ); + assign clk_main_hmac_en = clk_main_hmac_hint | ~idle_i[HintMainHmac]; prim_flop_2sync #( @@ -761,15 +908,33 @@ .lc_en_o(clk_main_hmac_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic clk_main_hmac_combined_en; + prim_buf u_prim_buf_clk_main_hmac_en ( + .in_i(clk_main_hmac_en & clk_main_en), + .out_o(clk_main_hmac_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_clk_main_hmac_cg ( .clk_i(clk_main_root), - .en_i(clk_main_hmac_en & clk_main_en), + .en_i(clk_main_hmac_combined_en), .test_en_i(clk_main_hmac_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_main_hmac) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_main_hmac ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_hmac_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_hmac) + ); + assign clk_main_kmac_en = clk_main_kmac_hint | ~idle_i[HintMainKmac]; prim_flop_2sync #( @@ -792,15 +957,33 @@ .lc_en_o(clk_main_kmac_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic clk_main_kmac_combined_en; + prim_buf u_prim_buf_clk_main_kmac_en ( + .in_i(clk_main_kmac_en & clk_main_en), + .out_o(clk_main_kmac_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_clk_main_kmac_cg ( .clk_i(clk_main_root), - .en_i(clk_main_kmac_en & clk_main_en), + .en_i(clk_main_kmac_combined_en), .test_en_i(clk_main_kmac_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_main_kmac) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_main_kmac ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_kmac_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_kmac) + ); + assign clk_main_otbn_en = clk_main_otbn_hint | ~idle_i[HintMainOtbn]; prim_flop_2sync #( @@ -823,15 +1006,33 @@ .lc_en_o(clk_main_otbn_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic clk_main_otbn_combined_en; + prim_buf u_prim_buf_clk_main_otbn_en ( + .in_i(clk_main_otbn_en & clk_main_en), + .out_o(clk_main_otbn_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_clk_main_otbn_cg ( .clk_i(clk_main_root), - .en_i(clk_main_otbn_en & clk_main_en), + .en_i(clk_main_otbn_combined_en), .test_en_i(clk_main_otbn_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_main_otbn) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_main_otbn ( + .clk_i(clk_main_i), + .rst_ni(rst_main_ni), + .lc_en_i(((clk_main_otbn_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_main_otbn) + ); + assign clk_io_div4_otbn_en = clk_io_div4_otbn_hint | ~idle_i[HintIoDiv4Otbn]; prim_flop_2sync #( @@ -854,15 +1055,33 @@ .lc_en_o(clk_io_div4_otbn_scanmode) ); + // Add a prim buf here to make sure the CG and the lc sender inputs + // are derived from the same physical signal. + logic clk_io_div4_otbn_combined_en; + prim_buf u_prim_buf_clk_io_div4_otbn_en ( + .in_i(clk_io_div4_otbn_en & clk_io_div4_en), + .out_o(clk_io_div4_otbn_combined_en) + ); + prim_clock_gating #( .FpgaBufGlobal(1'b0) // This clock is used primarily locally. ) u_clk_io_div4_otbn_cg ( .clk_i(clk_io_div4_root), - .en_i(clk_io_div4_otbn_en & clk_io_div4_en), + .en_i(clk_io_div4_otbn_combined_en), .test_en_i(clk_io_div4_otbn_scanmode == lc_ctrl_pkg::On), .clk_o(clocks_o.clk_io_div4_otbn) ); + // clock gated indication for alert handler + prim_lc_sender #( + .ResetValueIsOn(1) + ) u_prim_lc_sender_clk_io_div4_otbn ( + .clk_i(clk_io_div4_i), + .rst_ni(rst_io_div4_ni), + .lc_en_i(((clk_io_div4_otbn_combined_en) ? lc_ctrl_pkg::Off : lc_ctrl_pkg::On)), + .lc_en_o(cg_en_o.clk_io_div4_otbn) + ); + // state readback assign hw2reg.clk_hints_status.clk_main_aes_val.de = 1'b1; @@ -895,5 +1114,6 @@ `ASSERT_KNOWN(LcCtrlClkBypAckKnownO_A, lc_clk_byp_ack_o) `ASSERT_KNOWN(JitterEnableKnownO_A, jitter_en_o) `ASSERT_KNOWN(ClocksKownO_A, clocks_o) + `ASSERT_KNOWN(CgEnKnownO_A, cg_en_o) endmodule // clkmgr
diff --git a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv index 223acf4..c78c40d 100644 --- a/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv +++ b/hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr_pkg.sv
@@ -20,6 +20,7 @@ HintMainOtbn = 4 } hint_names_e; + // clocks generated and broadcast typedef struct packed { logic clk_io_div4_powerup; logic clk_aon_powerup; @@ -46,9 +47,39 @@ logic clk_io_div2_peri; logic clk_io_peri; logic clk_usb_peri; - } clkmgr_out_t; + // clock gating indication for alert handler + typedef struct packed { + lc_ctrl_pkg::lc_tx_t clk_io_div4_powerup; + lc_ctrl_pkg::lc_tx_t clk_aon_powerup; + lc_ctrl_pkg::lc_tx_t clk_main_powerup; + lc_ctrl_pkg::lc_tx_t clk_io_powerup; + lc_ctrl_pkg::lc_tx_t clk_usb_powerup; + lc_ctrl_pkg::lc_tx_t clk_io_div2_powerup; + lc_ctrl_pkg::lc_tx_t clk_aon_infra; + lc_ctrl_pkg::lc_tx_t clk_aon_secure; + lc_ctrl_pkg::lc_tx_t clk_aon_peri; + lc_ctrl_pkg::lc_tx_t clk_aon_timers; + lc_ctrl_pkg::lc_tx_t clk_main_aes; + lc_ctrl_pkg::lc_tx_t clk_main_hmac; + lc_ctrl_pkg::lc_tx_t clk_main_kmac; + lc_ctrl_pkg::lc_tx_t clk_main_otbn; + lc_ctrl_pkg::lc_tx_t clk_io_div4_otbn; + lc_ctrl_pkg::lc_tx_t clk_io_div4_infra; + lc_ctrl_pkg::lc_tx_t clk_main_infra; + lc_ctrl_pkg::lc_tx_t clk_io_div4_secure; + lc_ctrl_pkg::lc_tx_t clk_main_secure; + lc_ctrl_pkg::lc_tx_t clk_usb_secure; + lc_ctrl_pkg::lc_tx_t clk_io_div4_timers; + lc_ctrl_pkg::lc_tx_t clk_io_div4_peri; + lc_ctrl_pkg::lc_tx_t clk_io_div2_peri; + lc_ctrl_pkg::lc_tx_t clk_io_peri; + lc_ctrl_pkg::lc_tx_t clk_usb_peri; + } clkmgr_cg_en_t; + + parameter int NumOutputClk = 25; + typedef struct packed { logic [5-1:0] idle;
diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv index 77b12e5..680198d 100644 --- a/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv +++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey.sv
@@ -1570,6 +1570,7 @@ // Inter-module signals .clocks_o(clkmgr_aon_clocks), + .cg_en_o(), .lc_dft_en_i(lc_ctrl_lc_dft_en), .ast_clk_byp_req_o(ast_clk_byp_req_o), .ast_clk_byp_ack_i(ast_clk_byp_ack_i),