blob: da72b2cf0de096c4b4c83b106320fd86d94a92e8 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// OTP Controller top.
//
`include "prim_assert.sv"
module otp_ctrl
import otp_ctrl_pkg::*;
import otp_ctrl_reg_pkg::*;
(
input clk_i,
input rst_ni,
// TODO: signals to AST
// Bus Interface (device)
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o,
// Interrupt Requests
output logic intr_otp_access_done_o,
output logic intr_otp_ctrl_err_o,
// Alerts
input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i,
output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o,
// Power manager interface
input pwr_otp_init_req_t pwr_otp_init_req_i,
output pwr_otp_init_rsp_t pwr_otp_init_rsp_o,
output otp_pwr_state_t otp_pwr_state_o,
// Lifecycle transition command interface
input lc_otp_program_req_t lc_otp_program_req_i,
output lc_otp_program_rsp_t lc_otp_program_rsp_o,
// Lifecycle broadcast inputs
input lc_tx_t lc_provision_en_i,
input lc_tx_t lc_test_en_i,
// OTP broadcast outputs
output otp_lc_data_t otp_lc_data_o,
output keymgr_key_t otp_keymgr_key_o,
output flash_key_t otp_flash_key_o
// TODO: other hardware broadcast outputs
);
//////////////////////////////////
// Regfile Breakout and Mapping //
//////////////////////////////////
tlul_pkg::tl_h2d_t tl_win_h2d[2];
tlul_pkg::tl_d2h_t tl_win_d2h[2];
otp_ctrl_reg_pkg::otp_ctrl_reg2hw_t reg2hw;
otp_ctrl_reg_pkg::otp_ctrl_hw2reg_t hw2reg;
otp_ctrl_reg_top u_reg (
.clk_i ,
.rst_ni,
.tl_i,
.tl_o,
.tl_win_o ( tl_win_h2d ),
.tl_win_i ( tl_win_d2h ),
.reg2hw ( reg2hw ),
.hw2reg ( hw2reg ),
.devmode_i( 1'b1 )
);
////////////////
// Interrupts //
////////////////
logic otp_access_done;
logic otp_ctrl_err;
// dummy connections
assign otp_access_done = reg2hw.direct_access_size.q[0];
assign otp_ctrl_err = reg2hw.direct_access_size.q[1];
prim_intr_hw #(
.Width(1)
) i_intr_esc0 (
.event_intr_i ( otp_access_done ),
.reg2hw_intr_enable_q_i ( reg2hw.intr_enable.otp_access_done.q ),
.reg2hw_intr_test_q_i ( reg2hw.intr_test.otp_access_done.q ),
.reg2hw_intr_test_qe_i ( reg2hw.intr_test.otp_access_done.qe ),
.reg2hw_intr_state_q_i ( reg2hw.intr_state.otp_access_done.q ),
.hw2reg_intr_state_de_o ( hw2reg.intr_state.otp_access_done.de ),
.hw2reg_intr_state_d_o ( hw2reg.intr_state.otp_access_done.d ),
.intr_o ( intr_otp_access_done_o )
);
prim_intr_hw #(
.Width(1)
) i_intr_esc1 (
.event_intr_i ( otp_ctrl_err ),
.reg2hw_intr_enable_q_i ( reg2hw.intr_enable.otp_ctrl_err.q ),
.reg2hw_intr_test_q_i ( reg2hw.intr_test.otp_ctrl_err.q ),
.reg2hw_intr_test_qe_i ( reg2hw.intr_test.otp_ctrl_err.qe ),
.reg2hw_intr_state_q_i ( reg2hw.intr_state.otp_ctrl_err.q ),
.hw2reg_intr_state_de_o ( hw2reg.intr_state.otp_ctrl_err.de ),
.hw2reg_intr_state_d_o ( hw2reg.intr_state.otp_ctrl_err.d ),
.intr_o ( intr_otp_ctrl_err_o )
);
///////////////////
// Alert Senders //
///////////////////
logic parity_mismatch;
logic digest_mismatch;
// dummy connections
assign parity_mismatch = reg2hw.direct_access_cmd.read.q &&
reg2hw.direct_access_cmd.read.qe;
assign digest_mismatch = reg2hw.direct_access_cmd.write.q &&
reg2hw.direct_access_cmd.write.qe;
prim_alert_sender #(
.AsyncOn(AlertAsyncOn[0])
) i_prim_alert_sender0 (
.clk_i,
.rst_ni,
.alert_i ( parity_mismatch ),
.alert_rx_i ( alert_rx_i[0] ),
.alert_tx_o ( alert_tx_o[0] )
);
prim_alert_sender #(
.AsyncOn(AlertAsyncOn[1])
) i_prim_alert_sender1 (
.clk_i,
.rst_ni,
.alert_i ( digest_mismatch ),
.alert_rx_i ( alert_rx_i[1] ),
.alert_tx_o ( alert_tx_o[1] )
);
///////////////
// OTP Macro //
///////////////
localparam int OtpWidth = 8;
localparam int OtpDepth = 1024;
localparam int OtpAddrWidth = $clog2(OtpDepth);
localparam int OtpErrWidth = 8;
logic otp_init_req, otp_init_done;
logic otp_err_valid;
logic [OtpErrWidth-1:0] otp_err_code;
logic otp_valid, otp_ready;
logic [OtpAddrWidth-1:0] otp_addr;
logic [OtpWidth-1:0] otp_wdata, otp_rdata;
logic otp_wren, otp_rvalid;
// a couple of dummy connections to the OTP macro
assign otp_valid = reg2hw.direct_access_wdata[1].qe | reg2hw.direct_access_cmd.write.qe;
assign otp_wren = reg2hw.direct_access_wdata[1].qe;
assign otp_addr = reg2hw.direct_access_address.q;
assign otp_wdata = reg2hw.direct_access_wdata[1].q[OtpWidth-1:0];
assign otp_init_req = 1'b1;
prim_otp #(
.Width(OtpWidth),
.Depth(OtpDepth),
.ErrWidth(OtpErrWidth)
) i_prim_otp (
.clk_i,
.rst_ni,
// Test inerface
.test_tl_i ( tl_win_h2d[1] ),
.test_tl_o ( tl_win_d2h[1] ),
// Init and error signals
.init_req_i ( otp_init_req ),
.init_done_o ( otp_init_done ),
.err_valid_o ( otp_err_valid ),
.err_code_o ( otp_err_code ),
// Read / Write command interface
.ready_o ( otp_ready ),
.valid_i ( otp_valid ),
.addr_i ( otp_addr ),
.wdata_i ( otp_wdata ),
.wren_i ( otp_wren ),
// Read data out
.rdata_o ( otp_rdata ),
.rvalid_o ( otp_rvalid )
);
////////////////////
// OTP Ctrl Logic //
////////////////////
logic [31:0] gate_gen_out;
logic gate_gen_out_valid;
// gate generator with dummy connection to regfile
prim_gate_gen #(
.NumGates(30000)
) i_prim_gate_gen (
.clk_i,
.rst_ni,
.data_i ( reg2hw.direct_access_wdata[0].q ),
.valid_i ( reg2hw.direct_access_wdata[0].qe ),
.data_o ( gate_gen_out ),
.valid_o ( gate_gen_out_valid )
);
/////////////////////
// PRESENT ENC/DEC //
/////////////////////
logic [63:0] otp_scrambler_out;
logic otp_scrambler_out_valid;
otp_ctrl_scrmbl i_otp_ctrl_scrmbl (
.clk_i,
.rst_ni,
.data_i ( {reg2hw.direct_access_wdata[1].q,
reg2hw.direct_access_wdata[0].q} ),
.cmd_i ( otp_scrmbl_cmd_e'(reg2hw.direct_access_wdata[1].q[2:0]) ),
.valid_i ( reg2hw.direct_access_wdata[1].qe ),
.ready_o ( ),
.data_o ( otp_scrambler_out ),
.valid_o ( otp_scrambler_out_valid )
);
///////////////////////////////////
// Dummy Connections and Tie Off //
///////////////////////////////////
always_comb begin : p_tie_off_or_connect
// tie off
hw2reg.status = '0;
hw2reg.err_code = '0;
hw2reg.direct_access_rdata = '0;
hw2reg.lc_state = '0;
hw2reg.id_state = '0;
hw2reg.test_xxx_cnt = '0;
hw2reg.transition_cnt = '0;
hw2reg.secret_integrity_digest = '0;
hw2reg.hw_cfg_lock = '0;
hw2reg.hw_cfg = '0;
hw2reg.hw_cfg_integrity_digest = '0;
hw2reg.sw_cfg_integrity_digest = '0;
// TODO: initialization should only performed once after reset. subsequent
// init requests should just be immediately ack'ed without performing the complete
// OTP boot sequence.
pwr_otp_init_rsp_o = '0;
otp_pwr_state_o = '0;
lc_otp_program_rsp_o = '0;
otp_lc_data_o = '0;
otp_keymgr_key_o = '0;
otp_flash_key_o = '0;
// dummy connections
{hw2reg.direct_access_rdata[0].d,
hw2reg.direct_access_rdata[1].d} = otp_scrambler_out ^ {gate_gen_out, gate_gen_out};
hw2reg.direct_access_rdata[0].de = gate_gen_out_valid ^ gate_gen_out_valid;
hw2reg.direct_access_rdata[1].de = gate_gen_out_valid ^ gate_gen_out_valid;
hw2reg.lc_state[0] = otp_rdata ^ {8{otp_rvalid}};
end
endmodule : otp_ctrl