diff --git a/hw/ip/sram_ctrl/data/sram_ctrl.hjson b/hw/ip/sram_ctrl/data/sram_ctrl.hjson index 1e12ef296aaf8..b223825eca856 100644 --- a/hw/ip/sram_ctrl/data/sram_ctrl.hjson +++ b/hw/ip/sram_ctrl/data/sram_ctrl.hjson @@ -366,7 +366,7 @@ before triggering a key renewal, hardware will automatically clear that status bit such that software can poll its status. Note that requesting a new scrambling key takes ~200 OTP cycles, which translates to ~800 CPU cycles (OTP runs at 24MHz, CPU runs at 100MHz). Note that writing 1 to this register while - a key request is pending has no effect. + a key request or a memory initialization request is already pending has no effect. ''' }, { bits: "1", @@ -376,7 +376,8 @@ The init mechanism uses an LFSR that is seeded with a part of the nonce supplied when requesting a scrambling key. Once seeded, the memory is initialized with pseudo-random data pulled from the LFSR. Note that !!CTRL.RENEW_SCR_KEY takes priority when writing 1 to both !!CTRL.RENEW_SCR_KEY and !!CTRL.INIT with the same write transaction. - This means that the key request will complete first, followed by SRAM initialization. + This means that the key request will complete first, followed by SRAM initialization. Note that writing 1 to this register while + an init request is already pending has no effect. ''' }, ] diff --git a/hw/ip/sram_ctrl/doc/registers.md b/hw/ip/sram_ctrl/doc/registers.md index ed28ed308e98e..8504937afd650 100644 --- a/hw/ip/sram_ctrl/doc/registers.md +++ b/hw/ip/sram_ctrl/doc/registers.md @@ -165,7 +165,8 @@ Write 1 to request memory init. The init mechanism uses an LFSR that is seeded with a part of the nonce supplied when requesting a scrambling key. Once seeded, the memory is initialized with pseudo-random data pulled from the LFSR. Note that [`CTRL.RENEW_SCR_KEY`](#ctrl) takes priority when writing 1 to both [`CTRL.RENEW_SCR_KEY`](#ctrl) and [`CTRL.INIT`](#ctrl) with the same write transaction. -This means that the key request will complete first, followed by SRAM initialization. +This means that the key request will complete first, followed by SRAM initialization. Note that writing 1 to this register while +an init request is already pending has no effect. ### CTRL . RENEW_SCR_KEY Write 1 to request a new scrambling key from OTP. After writing to this register, SRAM transactions will @@ -173,7 +174,7 @@ be blocked until [`STATUS.SCR_KEY_VALID`](#status) has been set to 1. If [`STATU before triggering a key renewal, hardware will automatically clear that status bit such that software can poll its status. Note that requesting a new scrambling key takes ~200 OTP cycles, which translates to ~800 CPU cycles (OTP runs at 24MHz, CPU runs at 100MHz). Note that writing 1 to this register while -a key request is pending has no effect. +a key request or a memory initialization request is already pending has no effect. ## SCR_KEY_ROTATED Clearable SRAM key request status. diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv index 4cf5588f76cdb..c9564b8a96fe4 100644 --- a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv +++ b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv @@ -205,10 +205,12 @@ module sram_ctrl // A write to the init register reloads the LFSR seed, resets the init counter and // sets init_q to flag a pending initialization request. - logic init_trig; - assign init_trig = reg2hw.ctrl.init.q & reg2hw.ctrl.init.qe; + logic init_trig, init_q; + assign init_trig = reg2hw.ctrl.init.q && + reg2hw.ctrl.init.qe && + !init_q; // Ignore new requests while memory init is already pending. - logic init_d, init_q, init_done; + logic init_d, init_done; assign init_d = (init_done) ? 1'b0 : (init_trig) ? 1'b1 : init_q; @@ -262,7 +264,11 @@ module sram_ctrl // the req/ack protocol as described in more details here: // https://docs.opentitan.org/hw/ip/otp_ctrl/doc/index.html#interfaces-to-sram-and-otbn-scramblers logic key_req, key_ack; - assign key_req = reg2hw.ctrl.renew_scr_key.q & reg2hw.ctrl.renew_scr_key.qe; + assign key_req = reg2hw.ctrl.renew_scr_key.q && + reg2hw.ctrl.renew_scr_key.qe && + !key_req_pending_q && // Ignore new requests while a request is already pending. + !init_q; // Ignore new requests while memory init is already pending. + assign key_req_pending_d = (key_req) ? 1'b1 : (key_ack) ? 1'b0 : key_req_pending_q;