[pinmux] Update pinmux implementation and add sleep/strap sampling features
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/pinmux/pinmux.core b/hw/ip/pinmux/pinmux.core
index 3e7d7e5..e32e3b8 100644
--- a/hw/ip/pinmux/pinmux.core
+++ b/hw/ip/pinmux/pinmux.core
@@ -11,7 +11,6 @@
- lowrisc:ip:pinmux_reg
- lowrisc:ip:pinmux_component
-
parameters:
SYNTHESIS:
datatype: bool
diff --git a/hw/ip/pinmux/pinmux_component.core b/hw/ip/pinmux/pinmux_component.core
index e405669..f130a7f 100644
--- a/hw/ip/pinmux/pinmux_component.core
+++ b/hw/ip/pinmux/pinmux_component.core
@@ -11,6 +11,8 @@
- lowrisc:ip:tlul
- lowrisc:prim:all
files:
+ - rtl/pinmux_pkg.sv
+ - rtl/pinmux_wkup.sv
- rtl/pinmux.sv
file_type: systemVerilogSource
diff --git a/hw/ip/pinmux/rtl/pinmux.sv b/hw/ip/pinmux/rtl/pinmux.sv
index bd6993d..bf79015 100644
--- a/hw/ip/pinmux/rtl/pinmux.sv
+++ b/hw/ip/pinmux/rtl/pinmux.sv
@@ -7,27 +7,59 @@
`include "prim_assert.sv"
-module pinmux (
- input clk_i,
- input rst_ni,
+module pinmux import pinmux_pkg::*; import pinmux_reg_pkg::*; (
+ input clk_i,
+ input rst_ni,
+ // Slow always-on clock
+ input clk_aon_i,
+ input rst_aon_ni,
+ // Wakeup request, running on clk_aon_i
+ output logic aon_wkup_req_o,
+ // Sleep enable, running on clk_i
+ input sleep_en_i,
+ // Strap sample request
+ input lc_strap_req_t lc_pinmux_strap_i,
+ output lc_strap_rsp_t lc_pinmux_strap_o,
// Bus Interface (device)
- input tlul_pkg::tl_h2d_t tl_i,
- output tlul_pkg::tl_d2h_t tl_o,
- // Peripheral side
- input [pinmux_reg_pkg::NPeriphOut-1:0] periph_to_mio_i,
- input [pinmux_reg_pkg::NPeriphOut-1:0] periph_to_mio_oe_i,
- output logic [pinmux_reg_pkg::NPeriphIn-1:0] mio_to_periph_o,
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+ // Muxed Peripheral side
+ input [NMioPeriphOut-1:0] periph_to_mio_i,
+ input [NMioPeriphOut-1:0] periph_to_mio_oe_i,
+ output logic [NMioPeriphIn-1:0] mio_to_periph_o,
+ // Dedicated Peripheral side
+ input [NDioPads-1:0] periph_to_dio_i,
+ input [NDioPads-1:0] periph_to_dio_oe_i,
+ output logic [NDioPads-1:0] dio_to_periph_o,
// Pad side
- output logic [pinmux_reg_pkg::NMioPads-1:0] mio_out_o,
- output logic [pinmux_reg_pkg::NMioPads-1:0] mio_oe_o,
- input [pinmux_reg_pkg::NMioPads-1:0] mio_in_i
+ // MIOs
+ output logic [NMioPads-1:0] mio_out_o,
+ output logic [NMioPads-1:0] mio_oe_o,
+ input [NMioPads-1:0] mio_in_i,
+ // DIOs
+ output logic [NDioPads-1:0] dio_out_o,
+ output logic [NDioPads-1:0] dio_oe_o,
+ input [NDioPads-1:0] dio_in_i
);
+ ////////////////////////////
+ // Parameters / Constants //
+ ////////////////////////////
+
+ // TODO: these need to be parameterizable via topgen at some point.
+ // They have been placed here such that they do not generate
+ // warnings in the C header generation step, since logic is not supported
+ // as a data type yet.
+ localparam logic [pinmux_reg_pkg::NMioPeriphOut-1:0] MioPeriphHasSleepMode = '1;
+ localparam logic [pinmux_reg_pkg::NDioPads-1:0] DioPeriphHasSleepMode = '1;
+ localparam logic [pinmux_reg_pkg::NDioPads-1:0] DioPeriphHasWkup = '1;
+
//////////////////////////////////
// Regfile Breakout and Mapping //
//////////////////////////////////
- pinmux_reg_pkg::pinmux_reg2hw_t reg2hw;
+ pinmux_reg2hw_t reg2hw;
+ pinmux_hw2reg_t hw2reg;
pinmux_reg_top i_reg_top (
.clk_i ,
@@ -35,15 +67,91 @@
.tl_i ,
.tl_o ,
.reg2hw ,
+ .hw2reg ,
.devmode_i(1'b1)
);
+ /////////////////////
+ // Sleep registers //
+ /////////////////////
+
+ logic sleep_en_q;
+ logic [NMioPads-1:0] mio_out_sleep_d, mio_oe_sleep_d;
+ logic [NMioPads-1:0] mio_out_sleep_q, mio_oe_sleep_q;
+ logic [NDioPads-1:0] dio_out_sleep_d, dio_oe_sleep_d;
+ logic [NDioPads-1:0] dio_out_sleep_q, dio_oe_sleep_q;
+ // these are external due to their WARL behavior
+ logic [NDioPads-1:0][1:0] dio_out_sleep_val_d, dio_out_sleep_val_q;
+
+ // latch MIO/DIO state when going to sleep
+ // 0: drive low
+ // 1: drive high
+ // 2: high-z
+ // 3: previous value
+ for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_sleep
+ assign mio_out_sleep_d[k] = (reg2hw.mio_out_sleep_val[k].q == 0) ? 1'b0 :
+ (reg2hw.mio_out_sleep_val[k].q == 1) ? 1'b1 :
+ (reg2hw.mio_out_sleep_val[k].q == 2) ? 1'b0 : mio_out_o[k];
+
+ assign mio_oe_sleep_d[k] = (reg2hw.mio_out_sleep_val[k].q == 0) ? 1'b1 :
+ (reg2hw.mio_out_sleep_val[k].q == 1) ? 1'b1 :
+ (reg2hw.mio_out_sleep_val[k].q == 2) ? 1'b0 : mio_oe_o[k];
+ end
+
+ // since DIO pads are permanently mapped to a specific peripheral,
+ // we only need to support retention regs on non-always on peripherals,
+ // outputs / inouts.
+ for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_sleep
+ if (DioPeriphHasSleepMode[k]) begin : gen_warl_connect
+ assign hw2reg.dio_out_sleep_val[k].d = dio_out_sleep_val_q[k];
+
+ assign dio_out_sleep_val_d[k] = (reg2hw.dio_out_sleep_val[k].qe) ?
+ reg2hw.dio_out_sleep_val[k].q :
+ dio_out_sleep_val_q[k];
+
+ assign dio_out_sleep_d[k] = (dio_out_sleep_val_q[k] == 0) ? 1'b0 :
+ (dio_out_sleep_val_q[k] == 1) ? 1'b1 :
+ (dio_out_sleep_val_q[k] == 2) ? 1'b0 : dio_out_o[k];
+
+ assign dio_oe_sleep_d[k] = (dio_out_sleep_val_q[k] == 0) ? 1'b1 :
+ (dio_out_sleep_val_q[k] == 1) ? 1'b1 :
+ (dio_out_sleep_val_q[k] == 2) ? 1'b0 : dio_oe_o[k];
+ end else begin : gen_warl_tie0
+ // these signals will be unused
+ assign hw2reg.dio_out_sleep_val[k].d = 2'b10; // default value defined in hjson
+ assign dio_out_sleep_val_d[k] = 2'b10; // default value defined in hjson
+ assign dio_out_sleep_d[k] = '0;
+ assign dio_oe_sleep_d[k] = '0;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin : p_sleep
+ if (!rst_ni) begin
+ sleep_en_q <= 1'b0;
+ dio_out_sleep_val_q <= {NDioPads{2'b10}}; // default value defined in hjson
+ mio_out_sleep_q <= '0;
+ mio_oe_sleep_q <= '0;
+ dio_out_sleep_q <= '0;
+ dio_oe_sleep_q <= '0;
+ end else begin
+ sleep_en_q <= sleep_en_i;
+ dio_out_sleep_val_q <= dio_out_sleep_val_d;
+
+ if (sleep_en_i & !sleep_en_q) begin
+ mio_out_sleep_q <= mio_out_sleep_d;
+ mio_oe_sleep_q <= mio_oe_sleep_d;
+ dio_out_sleep_q <= dio_out_sleep_d;
+ dio_oe_sleep_q <= dio_oe_sleep_d;
+ end
+ end
+ end
+
///////////////
// Input Mux //
///////////////
- for (genvar k = 0; k < pinmux_reg_pkg::NPeriphIn; k++) begin : gen_periph_in
- logic [2**$clog2(pinmux_reg_pkg::NMioPads+2)-1:0] data_mux;
+ for (genvar k = 0; k < NMioPeriphIn; k++) begin : gen_mio_periph_in
+ logic [2**$clog2(NMioPads+2)-1:0] data_mux;
// stack input and default signals for convenient indexing below
// possible defaults: constant 0 or 1
assign data_mux = $bits(data_mux)'({mio_in_i, 1'b1, 1'b0});
@@ -55,15 +163,110 @@
// Output Mux //
////////////////
- for (genvar k = 0; k < pinmux_reg_pkg::NMioPads; k++) begin : gen_mio_out
- logic [2**$clog2(pinmux_reg_pkg::NPeriphOut+3)-1:0] data_mux, oe_mux;
+ for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_out
+ logic sleep_en;
+ logic [2**$clog2(NMioPeriphOut+3)-1:0] data_mux, oe_mux, sleep_mux;
// stack output data/enable and default signals for convenient indexing below
// possible defaults: 0, 1 or 2 (high-Z)
- assign data_mux = $bits(data_mux)'({periph_to_mio_i, 1'b0, 1'b1, 1'b0});
- assign oe_mux = $bits(oe_mux)'({periph_to_mio_oe_i, 1'b0, 1'b1, 1'b1});
+ assign data_mux = $bits(data_mux)'({periph_to_mio_i, 1'b0, 1'b1, 1'b0});
+ assign oe_mux = $bits(oe_mux)'({periph_to_mio_oe_i, 1'b0, 1'b1, 1'b1});
+ assign sleep_mux = $bits(sleep_mux)'({MioPeriphHasSleepMode, 1'b1, 1'b1, 1'b1});
+
+ // check whether this peripheral can actually go to sleep
+ assign sleep_en = sleep_mux[reg2hw.mio_outsel[k].q] & sleep_en_q;
// index using configured outsel
- assign mio_out_o[k] = data_mux[reg2hw.mio_outsel[k].q];
- assign mio_oe_o[k] = oe_mux[reg2hw.mio_outsel[k].q];
+ assign mio_out_o[k] = (sleep_en) ? mio_out_sleep_q[k] : data_mux[reg2hw.mio_outsel[k].q];
+ assign mio_oe_o[k] = (sleep_en) ? mio_oe_sleep_q[k] : oe_mux[reg2hw.mio_outsel[k].q];
+ end
+
+ /////////////////////
+ // DIO connections //
+ /////////////////////
+
+ // Inputs are just fed through
+ assign dio_to_periph_o = dio_in_i;
+
+ for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_out
+ // Since this is a DIO, this can be determined at design time
+ if (DioPeriphHasSleepMode[k]) begin : gen_sleep
+ assign dio_out_o[k] = (sleep_en_q) ? dio_out_sleep_q[k] : periph_to_dio_i[k];
+ assign dio_oe_o[k] = (sleep_en_q) ? dio_oe_sleep_q[k] : periph_to_dio_oe_i[k];
+ end else begin : gen_nosleep
+ assign dio_out_o[k] = periph_to_dio_i[k];
+ assign dio_oe_o[k] = periph_to_dio_oe_i[k];
+ end
+ end
+
+ //////////////////////
+ // Wakeup detectors //
+ //////////////////////
+
+ localparam int AlignedMuxSize = (NMioPads + 2 > NDioPads) ? 2**$clog2(NMioPads + 2) :
+ 2**$clog2(NDioPads);
+ logic [NWkupDetect-1:0] aon_wkup_req;
+ logic [AlignedMuxSize-1:0] dio_data_mux, mio_data_mux;
+ assign mio_data_mux = AlignedMuxSize'({mio_in_i, 1'b0, 1'b0});
+
+ // Only connect DIOs that are not excempt
+ for (genvar k = 0; k < AlignedMuxSize; k++) begin : gen_dio_wkup
+ if (k < NDioPads && DioPeriphHasWkup[k]) begin : gen_dio_wkup_connect
+ assign dio_data_mux[k] = dio_in_i[k];
+ end else begin : gen_dio_tie_off
+ assign dio_data_mux[k] = 1'b0;
+ end
+ end
+
+ for (genvar k = 0; k < NWkupDetect; k++) begin : gen_wkup_detect
+ logic pin_value;
+ assign pin_value = (reg2hw.wkup_detector[k].miodio.q) ?
+ dio_data_mux[reg2hw.wkup_detector_padsel[k]] :
+ mio_data_mux[reg2hw.wkup_detector_padsel[k]];
+
+ pinmux_wkup i_pinmux_wkup (
+ .clk_i,
+ .rst_ni,
+ .clk_aon_i,
+ .rst_aon_ni,
+ // config signals. these are synched to clk_aon internally
+ .wkup_en_i ( reg2hw.wkup_detector_en[k].q ),
+ .filter_en_i ( reg2hw.wkup_detector[k].filter.q ),
+ .wkup_mode_i ( reg2hw.wkup_detector[k].mode.q ),
+ .wkup_cnt_th_i ( reg2hw.wkup_detector_cnt_th[k].q ),
+ .pin_value_i ( pin_value ),
+ // cause reg signals. these are synched from/to clk_aon internally
+ .wkup_cause_valid_i ( reg2hw.wkup_cause[k].qe ),
+ .wkup_cause_data_i ( reg2hw.wkup_cause[k].q ),
+ .wkup_cause_data_o ( hw2reg.wkup_cause[k].d ),
+ // wakeup request signals on clk_aon (level encoded)
+ .aon_wkup_req_o ( aon_wkup_req[k] )
+ );
+ end
+
+ // OR' together all wakeup requests
+ assign aon_wkup_req_o = |aon_wkup_req;
+
+ ////////////////////
+ // Strap Sampling //
+ ////////////////////
+
+ logic [NStraps-1:0] lc_strap_taps;
+ lc_strap_rsp_t lc_strap_d, lc_strap_q;
+
+ for (genvar k = 0; k < NStraps; k++) begin : gen_strap_taps
+ assign lc_strap_taps[k] = mio_in_i[MioStrapPos[k]];
+ end
+
+ assign lc_pinmux_strap_o = lc_strap_q;
+ assign lc_strap_d = (lc_pinmux_strap_i.sample_pulse) ?
+ '{valid: 1'b1, straps: lc_strap_taps} :
+ lc_strap_q;
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin : p_strap_sample
+ if (!rst_ni) begin
+ lc_strap_q <= '0;
+ end else begin
+ lc_strap_q <= lc_strap_d;
+ end
end
////////////////
@@ -72,8 +275,22 @@
`ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid)
`ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready)
- `ASSERT_KNOWN(MioToPeriphKnownO_A, mio_to_periph_o)
- `ASSERT_KNOWN(MioOutKnownO_A, mio_out_o)
+ // `ASSERT_KNOWN(MioToPeriphKnownO_A, mio_to_periph_o)
`ASSERT_KNOWN(MioOeKnownO_A, mio_oe_o)
+ // `ASSERT_KNOWN(DioToPeriphKnownO_A, dio_to_periph_o)
+ `ASSERT_KNOWN(DioOeKnownO_A, dio_oe_o)
+ `ASSERT_KNOWN(LcPinmuxStrapKnownO_A, lc_pinmux_strap_o)
+
+ // TODO: need to check why some outputs are not valid (e.g. SPI device MISO)
+ // for (genvar k = 0; k < NMioPads; k++) begin : gen_mio_known_if
+ // `ASSERT_KNOWN_IF(MioOutKnownO_A, mio_out_o[k], mio_oe_o[k])
+ // end
+
+ // for (genvar k = 0; k < NDioPads; k++) begin : gen_dio_known_if
+ // `ASSERT_KNOWN_IF(DioOutKnownO_A, dio_out_o[k], dio_oe_o[k])
+ // end
+
+ // running on slow AON clock
+ `ASSERT_KNOWN(AonWkupReqKnownO_A, aon_wkup_req_o, !rst_aon_ni, clk_aon_i)
endmodule : pinmux
diff --git a/hw/ip/pinmux/rtl/pinmux_pkg.sv b/hw/ip/pinmux/rtl/pinmux_pkg.sv
new file mode 100644
index 0000000..fe73341
--- /dev/null
+++ b/hw/ip/pinmux/rtl/pinmux_pkg.sv
@@ -0,0 +1,35 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package pinmux_pkg;
+
+ // Wakeup Detector Modes
+ typedef enum logic [2:0] {
+ Disabled = 3'b000,
+ Negedge = 3'b001,
+ Posedge = 3'b010,
+ Edge = 3'b011,
+ LowTimed = 3'b100,
+ HighTimed = 3'b101
+ } wkup_mode_e;
+
+ // Interface with LC controller
+ parameter int NStraps = 2;
+ // Strap sampling is only supported on MIOs at the moment
+ parameter int MioStrapPos [0:NStraps-1] = '{1, 0};
+
+ typedef struct packed {
+ logic sample_pulse;
+ } lc_strap_req_t;
+
+ parameter lc_strap_req_t LC_PINMUX_STRAP_REQ_DEFAULT = '{
+ sample_pulse: 1'b0
+ };
+
+ typedef struct packed {
+ logic valid;
+ logic [NStraps-1:0] straps;
+ } lc_strap_rsp_t;
+
+endpackage : pinmux_pkg
diff --git a/hw/ip/pinmux/rtl/pinmux_wkup.sv b/hw/ip/pinmux/rtl/pinmux_wkup.sv
new file mode 100644
index 0000000..58475e2
--- /dev/null
+++ b/hw/ip/pinmux/rtl/pinmux_wkup.sv
@@ -0,0 +1,198 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+module pinmux_wkup import pinmux_pkg::*; import pinmux_reg_pkg::*; #(
+ parameter Cycles = 4
+) (
+ input clk_i,
+ input rst_ni,
+ // Always on clock / reset
+ input clk_aon_i,
+ input rst_aon_ni,
+ // These signals get synchronized to the
+ // slow AON clock within this module.
+ // Note that wkup_en_i is assumed to be level encoded.
+ input wkup_en_i,
+ input filter_en_i,
+ input wkup_mode_e wkup_mode_i,
+ input [WkupCntWidth-1:0] wkup_cnt_th_i,
+ input pin_value_i,
+ // Signals to/from cause register.
+ // They are synched to/from the AON clock internally
+ input wkup_cause_valid_i,
+ input wkup_cause_data_i,
+ output wkup_cause_data_o,
+ // This signal is running on the AON clock
+ // and is held high as long as the cause register
+ // has not been cleared.
+ output logic aon_wkup_req_o
+);
+
+ ///////////////////////////
+ // Input Synchronization //
+ ///////////////////////////
+
+ // Synchronize configuration to slow clock
+ wkup_mode_e aon_wkup_mode_q;
+ logic aon_filter_en_q;
+ logic aon_wkup_en_d, aon_wkup_en_q;
+ logic [WkupCntWidth-1:0] aon_wkup_cnt_th_q;
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) i_prim_flop_2sync_config (
+ .clk_i ( clk_aon_i ),
+ .rst_ni ( rst_aon_ni ),
+ .d ( wkup_en_i ),
+ .q ( aon_wkup_en_d )
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_sync
+ if (!rst_aon_ni) begin
+ aon_wkup_en_q <= 1'b0;
+ aon_wkup_mode_q <= Disabled;
+ aon_filter_en_q <= 1'b0;
+ aon_wkup_cnt_th_q <= '0;
+ end else begin
+ aon_wkup_en_q <= aon_wkup_en_d;
+ // latch these when going into sleep. note that these
+ // config signals should be stable at this point, since
+ // SW has configured them many cycles ago. hence no
+ // explicit multibit consistency check is performed.
+ if (aon_wkup_en_d & !aon_wkup_en_q) begin
+ aon_wkup_mode_q <= wkup_mode_i;
+ aon_filter_en_q <= filter_en_i;
+ aon_wkup_cnt_th_q <= wkup_cnt_th_i;
+ end
+ end
+ end
+
+ ////////////////////////////
+ // Optional Signal Filter //
+ ////////////////////////////
+
+ // This uses a lower value for filtering than GPIO since
+ // the always-on clock is slower. This can be disabled,
+ // in which case the signal is just combinationally bypassed.
+ logic aon_filter_out, aon_filter_out_d, aon_filter_out_q;
+ prim_filter #(
+ .Cycles(Cycles)
+ ) i_prim_filter (
+ .clk_i ( clk_aon_i ),
+ .rst_ni ( rst_aon_ni ),
+ .enable_i ( aon_filter_en_q ),
+ .filter_i ( pin_value_i ),
+ .filter_o ( aon_filter_out )
+ );
+
+ // Run this through a 2 stage synchronizer to
+ // prevent metastability.
+ prim_flop_2sync #(
+ .Width(1)
+ ) i_prim_flop_2sync_filter (
+ .clk_i ( clk_aon_i ),
+ .rst_ni ( rst_aon_ni ),
+ .d ( aon_filter_out ),
+ .q ( aon_filter_out_d )
+ );
+
+ //////////////////////
+ // Pattern Matching //
+ //////////////////////
+
+ logic aon_rising, aon_falling;
+ assign aon_falling = ~aon_filter_out_d & aon_filter_out_q;
+ assign aon_rising = aon_filter_out_d & ~aon_filter_out_q;
+
+ logic aon_cnt_en, aon_cnt_eq_th;
+ logic [WkupCntWidth-1:0] aon_cnt_d, aon_cnt_q;
+ assign aon_cnt_d = (aon_cnt_eq_th) ? '0 :
+ (aon_cnt_en) ? aon_cnt_q + 1'b1 : '0;
+
+ assign aon_cnt_eq_th = aon_cnt_q == aon_wkup_cnt_th_q;
+
+ logic aon_wkup_pulse;
+ always_comb begin : p_mode
+ aon_wkup_pulse = 1'b0;
+ aon_cnt_en = 1'b0;
+ if (aon_wkup_en_q) begin
+ unique case (aon_wkup_mode_q)
+ Negedge: aon_wkup_pulse = aon_falling;
+ Posedge: aon_wkup_pulse = aon_rising;
+ Edge: aon_wkup_pulse = aon_rising | aon_falling;
+ LowTimed: begin
+ aon_cnt_en = ~aon_filter_out_d;
+ aon_wkup_pulse = aon_cnt_eq_th;
+ end
+ HighTimed: begin
+ aon_cnt_en = aon_filter_out_d;
+ aon_wkup_pulse = aon_cnt_eq_th;
+ end
+ default: ; // also covers "Disabled"
+ endcase
+ end
+ end
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_aon_pattern
+ if (!rst_aon_ni) begin
+ aon_filter_out_q <= 1'b0;
+ aon_cnt_q <= '0;
+ end else begin
+ aon_filter_out_q <= aon_filter_out_d;
+ aon_cnt_q <= aon_cnt_d;
+ end
+ end
+
+ ////////////////////
+ // Cause register //
+ ////////////////////
+
+ // to AON domain
+ logic aon_wkup_cause_valid, aon_wkup_cause_data;
+ logic aon_wkup_cause_d, aon_wkup_cause_q;
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) i_prim_flop_2sync_cause_in (
+ .clk_i ( clk_aon_i ),
+ .rst_ni ( rst_aon_ni ),
+ .d ( wkup_cause_data_i ),
+ .q ( aon_wkup_cause_data )
+ );
+
+ prim_pulse_sync i_prim_pulse_sync_cause (
+ .clk_src_i ( clk_i ),
+ .rst_src_ni ( rst_ni ),
+ .src_pulse_i ( wkup_cause_valid_i ),
+ .clk_dst_i ( clk_aon_i ),
+ .rst_dst_ni ( rst_aon_ni ),
+ .dst_pulse_o ( aon_wkup_cause_valid )
+ );
+
+ // note that aon_wkup_pulse will not be asserted when not in sleep mode
+ assign aon_wkup_cause_d = (aon_wkup_cause_valid) ? aon_wkup_cause_q & aon_wkup_cause_data :
+ aon_wkup_cause_q | aon_wkup_pulse;
+
+ // output to power manager
+ assign aon_wkup_req_o = aon_wkup_cause_q;
+
+ // output to CSR
+ prim_flop_2sync #(
+ .Width(1)
+ ) i_prim_flop_2sync_cause_out (
+ .clk_i,
+ .rst_ni,
+ .d ( aon_wkup_cause_q ),
+ .q ( wkup_cause_data_o )
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_aon_cause
+ if (!rst_aon_ni) begin
+ aon_wkup_cause_q <= 1'b0;
+ end else begin
+ aon_wkup_cause_q <= aon_wkup_cause_d;
+ end
+ end
+
+endmodule : pinmux_wkup