Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[otp_ctrl] Filter ECC errors in partitions with no integrity #21256

Merged
merged 1 commit into from
Feb 8, 2024
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
42 changes: 27 additions & 15 deletions hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ module otp_ctrl_dai
logic [NumPart-1:0][OtpAddrWidth-1:0] digest_addr_lut;
logic part_sel_valid;

// Depending on the partition configuration, the wrapper is instructed to ignore integrity
// calculations and checks. To be on the safe side, the partition filters error responses at this
// point and does not report any integrity errors if integrity is disabled.
otp_err_e otp_err;
always_comb begin
otp_err = otp_err_e'(otp_err_i);
if (!PartInfo[part_idx].integrity &&
otp_err_i inside {MacroEccCorrError, MacroEccUncorrError}) begin
otp_err = NoError;
end
end

// Output partition error state.
assign error_o = error_q;
// Working register is connected to data outputs.
Expand Down Expand Up @@ -235,9 +247,9 @@ module otp_ctrl_dai
init_done_o = 1'b0;
dai_prog_idle_o = 1'b0;
if (otp_rvalid_i) begin
if ((!(otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}))) begin
if ((!(otp_err inside {NoError, MacroEccCorrError}))) begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end else begin
state_d = InitPartSt;
end
Expand Down Expand Up @@ -332,7 +344,7 @@ module otp_ctrl_dai
digest_addr_lut[part_idx])) begin
if (otp_rvalid_i) begin
// Check OTP return code.
if (otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) begin
if (otp_err inside {NoError, MacroEccCorrError}) begin
data_en = 1'b1;
// We do not need to descramble the digest values.
if (PartInfo[part_idx].secret && otp_addr_o != digest_addr_lut[part_idx]) begin
Expand All @@ -342,12 +354,12 @@ module otp_ctrl_dai
dai_cmd_done_o = 1'b1;
end
// At this point the only error that we could have gotten are correctable ECC errors.
if (otp_err_e'(otp_err_i) != NoError) begin
if (otp_err != NoError) begin
error_d = MacroEccCorrError;
end
end else begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end
end
// At this point, this check MUST succeed - otherwise this means that
Expand Down Expand Up @@ -443,17 +455,17 @@ module otp_ctrl_dai

if (otp_rvalid_i) begin
// Check OTP return code. Note that non-blank errors are recoverable.
if ((!(otp_err_e'(otp_err_i) inside {NoError, MacroWriteBlankError}))) begin
if ((!(otp_err inside {NoError, MacroWriteBlankError}))) begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end else begin
// Clear working register state.
data_clr = 1'b1;
state_d = IdleSt;
dai_cmd_done_o = 1'b1;
// Signal non-blank state, but do not go to terminal error state.
if (otp_err_e'(otp_err_i) == MacroWriteBlankError) begin
error_d = otp_err_e'(otp_err_i);
if (otp_err == MacroWriteBlankError) begin
error_d = otp_err;
end
end
end
Expand Down Expand Up @@ -566,15 +578,15 @@ module otp_ctrl_dai
if (otp_rvalid_i) begin
cnt_en = 1'b1;
// Check OTP return code.
if ((!(otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}))) begin
if ((!(otp_err inside {NoError, MacroEccCorrError}))) begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end else begin
data_en = 1'b1;
state_d = DigSt;
// Signal soft ECC errors, but do not go into terminal error state.
if (otp_err_e'(otp_err_i) == MacroEccCorrError) begin
error_d = otp_err_e'(otp_err_i);
if (otp_err == MacroEccCorrError) begin
error_d = otp_err;
end
end
end
Expand Down Expand Up @@ -839,8 +851,8 @@ module otp_ctrl_dai
// OTP error response
`ASSERT(OtpErrorState_A,
state_q inside {InitOtpSt, ReadWaitSt, WriteWaitSt, DigReadWaitSt} && otp_rvalid_i &&
!(otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError, MacroWriteBlankError})
!(otp_err inside {NoError, MacroEccCorrError, MacroWriteBlankError})
|=>
state_q == ErrorSt && error_o == $past(otp_err_e'(otp_err_i)))
state_q == ErrorSt && error_o == $past(otp_err))

endmodule : otp_ctrl_dai
29 changes: 20 additions & 9 deletions hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,22 @@ module otp_ctrl_part_buf
// This partition cannot do any write accesses, hence we tie this
// constantly off.
assign otp_wdata_o = '0;
// Depending on the partition configuration, the wrapper is instructed to ignore integrity errors.
// Depending on the partition configuration, the wrapper is instructed to ignore integrity
// calculations and checks. To be on the safe side, the partition filters error responses at this
// point and does not report any integrity errors if integrity is disabled.
otp_err_e otp_err;
if (Info.integrity) begin : gen_integrity
assign otp_cmd_o = prim_otp_pkg::Read;
assign otp_err = otp_err_e'(otp_err_i);
end else begin : gen_no_integrity
assign otp_cmd_o = prim_otp_pkg::ReadRaw;
always_comb begin
if (otp_err_i inside {MacroEccCorrError, MacroEccUncorrError}) begin
otp_err = NoError;
end else begin
otp_err = otp_err_e'(otp_err_i);
end
end
end

always_comb begin : p_fsm
Expand Down Expand Up @@ -253,7 +264,7 @@ module otp_ctrl_part_buf
InitWaitSt: begin
if (otp_rvalid_i) begin
buffer_reg_en = 1'b1;
if (otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) begin
if (otp_err inside {NoError, MacroEccCorrError}) begin
// Once we've read and descrambled the whole partition, we can go to integrity
// verification. Note that the last block is the digest value, which does not
// have to be descrambled.
Expand All @@ -268,12 +279,12 @@ module otp_ctrl_part_buf
cnt_en = 1'b1;
end
// At this point the only error that we could have gotten are correctable ECC errors.
if (otp_err_e'(otp_err_i) != NoError) begin
if (otp_err != NoError) begin
error_d = MacroEccCorrError;
end
end else begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end
end
end
Expand Down Expand Up @@ -349,7 +360,7 @@ module otp_ctrl_part_buf
// SEC_CM: PART.DATA_REG.BKGN_CHK
CnstyReadWaitSt: begin
if (otp_rvalid_i) begin
if (otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) begin
if (otp_err inside {NoError, MacroEccCorrError}) begin
// Check whether we need to compare the digest or the full partition
// contents here.
if (Info.hw_digest) begin
Expand Down Expand Up @@ -387,12 +398,12 @@ module otp_ctrl_part_buf
end
end
// At this point the only error that we could have gotten are correctable ECC errors.
if (otp_err_e'(otp_err_i) != NoError) begin
if (otp_err != NoError) begin
error_d = MacroEccCorrError;
end
end else begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
// The check has finished and found an error.
cnsty_chk_ack_o = 1'b1;
end
Expand Down Expand Up @@ -799,8 +810,8 @@ module otp_ctrl_part_buf
// OTP error response
`ASSERT(OtpErrorState_A,
state_q inside {InitWaitSt, CnstyReadWaitSt} && otp_rvalid_i &&
!(otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) && !ecc_err
!(otp_err inside {NoError, MacroEccCorrError}) && !ecc_err
|=>
state_q == ErrorSt && error_o == $past(otp_err_e'(otp_err_i)))
state_q == ErrorSt && error_o == $past(otp_err))

endmodule : otp_ctrl_part_buf
29 changes: 20 additions & 9 deletions hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,22 @@ module otp_ctrl_part_unbuf
// This partition cannot do any write accesses, hence we tie this
// constantly off.
assign otp_wdata_o = '0;
// Depending on the partition configuration, the wrapper is instructed to ignore integrity errors.
// Depending on the partition configuration, the wrapper is instructed to ignore integrity
// calculations and checks. To be on the safe side, the partition filters error responses at this
// point and does not report any integrity errors if integrity is disabled.
otp_err_e otp_err;
if (Info.integrity) begin : gen_integrity
assign otp_cmd_o = prim_otp_pkg::Read;
assign otp_err = otp_err_e'(otp_err_i);
end else begin : gen_no_integrity
assign otp_cmd_o = prim_otp_pkg::ReadRaw;
always_comb begin
if (otp_err_i inside {MacroEccCorrError, MacroEccUncorrError}) begin
otp_err = NoError;
end else begin
otp_err = otp_err_e'(otp_err_i);
end
end
end

`ASSERT_KNOWN(FsmStateKnown_A, state_q)
Expand Down Expand Up @@ -203,15 +214,15 @@ module otp_ctrl_part_unbuf
InitWaitSt: begin
if (otp_rvalid_i) begin
digest_reg_en = 1'b1;
if (otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) begin
if (otp_err inside {NoError, MacroEccCorrError}) begin
state_d = IdleSt;
// At this point the only error that we could have gotten are correctable ECC errors.
if (otp_err_e'(otp_err_i) != NoError) begin
if (otp_err != NoError) begin
error_d = MacroEccCorrError;
end
end else begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
end
end
end
Expand Down Expand Up @@ -255,15 +266,15 @@ module otp_ctrl_part_unbuf
init_done_o = 1'b1;
if (otp_rvalid_i) begin
tlul_rvalid_o = 1'b1;
if (otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) begin
if (otp_err inside {NoError, MacroEccCorrError}) begin
state_d = IdleSt;
// At this point the only error that we could have gotten are correctable ECC errors.
if (otp_err_e'(otp_err_i) != NoError) begin
if (otp_err != NoError) begin
error_d = MacroEccCorrError;
end
end else begin
state_d = ErrorSt;
error_d = otp_err_e'(otp_err_i);
error_d = otp_err;
// This causes the TL-UL adapter to return a bus error.
tlul_rerror_o = 2'b11;
end
Expand Down Expand Up @@ -513,8 +524,8 @@ module otp_ctrl_part_unbuf
// OTP error response
`ASSERT(OtpErrorState_A,
state_q inside {InitWaitSt, ReadWaitSt} && otp_rvalid_i &&
!(otp_err_e'(otp_err_i) inside {NoError, MacroEccCorrError}) && !ecc_err
!(otp_err inside {NoError, MacroEccCorrError}) && !ecc_err
|=>
state_q == ErrorSt && error_o == $past(otp_err_e'(otp_err_i)))
state_q == ErrorSt && error_o == $past(otp_err))

endmodule : otp_ctrl_part_unbuf
Loading