blob: b5e564b290be77df4a827870c074eae276df1bf1 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Flash Phy Module
//
//
// Flash phy represents the top level open source wrapper for a proprietary flash
// module.
// The top level flash_phy is only responsible for dispatching transactions and
// correctly collecting the responses in order.
module flash_phy
import flash_ctrl_pkg::*;
import prim_mubi_pkg::mubi4_t;
#(
parameter bit SecScrambleEn = 1'b1,
parameter int ModelOnlyReadLatency = 1, // generic model read latency
parameter int ModelOnlyProgLatency = 50, // generic model program latency
parameter int ModelOnlyEraseLatency = 200 // generic model program latency
)
(
input clk_i,
input rst_ni,
input host_req_i,
input [BusAddrW-1:0] host_addr_i,
output logic host_req_rdy_o,
output logic host_req_done_o,
output logic [BusFullWidth-1:0] host_rdata_o,
output logic host_rderr_o,
input flash_req_t flash_ctrl_i,
output flash_rsp_t flash_ctrl_o,
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o,
input mubi4_t scanmode_i,
input scan_en_i,
input scan_rst_ni,
input flash_power_ready_h_i,
input flash_power_down_h_i,
inout [1:0] flash_test_mode_a_io,
inout flash_test_voltage_h_io,
input mubi4_t flash_bist_enable_i,
input lc_ctrl_pkg::lc_tx_t lc_nvm_debug_en_i,
input ast_pkg::ast_obs_ctrl_t obs_ctrl_i,
output logic [7:0] fla_obs_o,
output ast_pkg::ast_dif_t flash_alert_o
);
import prim_mubi_pkg::MuBi4False;
// Flash macro outstanding refers to how many reads we allow a macro to move ahead of an
// in order blocking read. Since the data cannot be returned out of order, this simply
// does the reads in advance and store them in a FIFO
localparam int FlashMacroOustanding = 1;
localparam int SeqFifoDepth = FlashMacroOustanding * NumBanks;
// flash_phy forwards incoming host transactions to the appropriate bank. However, depending
// on the transaction type, the completion times may differ (for example, a transaction
// requiring de-scramble will take significantly longer than one that hits in the read buffers).
// This implies that it is possible for flash_phy to forward one transaction to bank N and another
// to bank N+1 only for bank N+1 to finish its transaction first.
//
// This suggests that even though transactions are received in-order, they can complete out of
// order. Thus it is the responsibility of the flash_phy to sequence the responses correctly.
// For banks that have finished ahead of time, it is also important to hold their output until
// consumption by the host.
//
// The sequence fifo below holds the correct response order, while each flash_phy_core is
// paired with a small passthrough response FIFO to hold the data if necessary.
// If one bank finishes "ahead" of schedule, the response FIFO will hold the response, and no new
// transactions will be issued to that bank until the response is consumed by the host.
// host to flash_phy interface
logic [BankW-1:0] host_bank_sel;
logic [BankW-1:0] rsp_bank_sel;
logic [NumBanks-1:0] host_req_rdy;
logic [NumBanks-1:0] host_req_done;
logic [NumBanks-1:0] host_rsp_avail;
logic [NumBanks-1:0] host_rsp_vld;
logic [NumBanks-1:0] host_rsp_ack;
logic [BusFullWidth-1:0] host_rsp_data [NumBanks];
logic [NumBanks-1:0] host_rsp_err;
logic seq_fifo_rdy;
logic seq_fifo_pending;
// flash_ctrl to flash_phy interface
logic [BankW-1:0] ctrl_bank_sel;
logic [NumBanks-1:0] rd_done;
logic [NumBanks-1:0] prog_done;
logic [NumBanks-1:0] erase_done;
logic init_busy;
logic [ProgTypes-1:0] prog_type_avail;
// common interface
logic [BusFullWidth-1:0] rd_data [NumBanks];
logic [NumBanks-1:0] rd_err;
logic [NumBanks-1:0] spurious_acks;
// fsm error per bank
logic [NumBanks-1:0] fsm_err;
// integrity error per bank
logic [NumBanks-1:0] prog_intg_err;
logic [NumBanks-1:0] relbl_ecc_err;
logic [NumBanks-1:0] intg_ecc_err;
// consistency error per bank
logic [NumBanks-1:0] arb_err;
logic [NumBanks-1:0] host_gnt_err;
// fifo error per bank
logic [NumBanks-1:0] rsp_fifo_err;
logic [NumBanks-1:0] core_fifo_err;
// select which bank each is operating on
assign host_bank_sel = host_req_i ? host_addr_i[BusAddrW-1 -: BankW] : '0;
assign ctrl_bank_sel = flash_ctrl_i.addr[BusAddrW-1 -: BankW];
// accept transaction if bank is ready and previous response NOT pending
assign host_req_rdy_o = host_req_rdy[host_bank_sel] & host_rsp_avail[host_bank_sel] &
seq_fifo_rdy;
assign host_req_done_o = seq_fifo_pending & host_rsp_vld[rsp_bank_sel];
assign host_rderr_o = host_rsp_err[rsp_bank_sel];
assign host_rdata_o = host_rsp_data[rsp_bank_sel];
// all banks are assumed to be the same in terms of prog_type support
assign flash_ctrl_o.prog_type_avail = prog_type_avail;
assign flash_ctrl_o.rd_done = rd_done[ctrl_bank_sel];
assign flash_ctrl_o.prog_done = prog_done[ctrl_bank_sel];
assign flash_ctrl_o.erase_done = erase_done[ctrl_bank_sel];
assign flash_ctrl_o.rd_data = rd_data[ctrl_bank_sel];
assign flash_ctrl_o.rd_err = rd_err[ctrl_bank_sel];
assign flash_ctrl_o.init_busy = init_busy;
assign flash_ctrl_o.prog_intg_err = |prog_intg_err;
assign flash_ctrl_o.storage_relbl_err = |relbl_ecc_err;
assign flash_ctrl_o.storage_intg_err = |intg_ecc_err;
assign flash_ctrl_o.fsm_err = |fsm_err;
assign flash_ctrl_o.spurious_ack = |spurious_acks;
assign flash_ctrl_o.arb_err = |arb_err;
assign flash_ctrl_o.host_gnt_err = |host_gnt_err;
assign flash_ctrl_o.fifo_err = |{rsp_fifo_err, core_fifo_err};
// This fifo holds the expected return order
prim_fifo_sync #(
.Width (BankW),
.Pass (0),
.Depth (SeqFifoDepth)
) u_bank_sequence_fifo (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid_i(host_req_i & host_req_rdy_o),
.wready_o(seq_fifo_rdy),
.wdata_i (host_bank_sel),
.depth_o (),
.full_o (),
.rvalid_o(seq_fifo_pending),
.rready_i(host_req_done_o),
.rdata_o (rsp_bank_sel),
.err_o ()
);
// Generate host scramble_en indication, broadcasted to all banks
localparam int TotalRegions = MpRegions + 1;
logic host_scramble_en, host_ecc_en;
data_region_attr_t region_attrs [TotalRegions];
mp_region_cfg_t region_cfg, unused_cfg;
for(genvar i = 0; i < TotalRegions; i++) begin : gen_region_attrs
assign region_attrs[i].phase = PhaseInvalid;
assign region_attrs[i].cfg = flash_ctrl_i.region_cfgs[i];
end
// the region decode only accepts page address
flash_mp_data_region_sel #(
.Regions(TotalRegions)
) u_region_sel (
.req_i(host_req_i),
.phase_i(PhaseInvalid),
.addr_i(host_addr_i[BusAddrW-1 -: AllPagesW]),
.region_attrs_i(region_attrs),
.sel_cfg_o(region_cfg)
);
// most attributes are unused
assign unused_cfg = region_cfg;
// only scramble/ecc attributes are looked at
import prim_mubi_pkg::mubi4_test_true_strict;
import prim_mubi_pkg::mubi4_and_hi;
assign host_scramble_en = mubi4_test_true_strict(
mubi4_and_hi(region_cfg.scramble_en, region_cfg.en));
assign host_ecc_en = mubi4_test_true_strict(mubi4_and_hi(region_cfg.ecc_en, region_cfg.en));
// Prim flash to flash_phy_core connections
flash_phy_pkg::flash_phy_prim_flash_req_t [NumBanks-1:0] prim_flash_req;
flash_phy_pkg::flash_phy_prim_flash_rsp_t [NumBanks-1:0] prim_flash_rsp;
logic [NumBanks-1:0] ecc_single_err;
logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr;
assign flash_ctrl_o.ecc_single_err = ecc_single_err;
assign flash_ctrl_o.ecc_addr = ecc_addr;
mubi4_t [NumBanks-1:0] flash_disable;
prim_mubi4_sync #(
.NumCopies(NumBanks),
.AsyncOn(0)
) u_disable_buf (
.clk_i,
.rst_ni,
.mubi_i(flash_ctrl_i.flash_disable),
.mubi_o(flash_disable)
);
for (genvar bank = 0; bank < NumBanks; bank++) begin : gen_flash_cores
// pop if the response came from the appropriate fifo
assign host_rsp_ack[bank] = host_req_done_o & (rsp_bank_sel == bank);
prim_fifo_sync #(
.Width (BusFullWidth + 1),
.Pass (1'b1),
.Depth (FlashMacroOustanding),
.Secure (1'b1)
) u_host_rsp_fifo (
.clk_i,
.rst_ni,
.clr_i (1'b0),
.wvalid_i(host_req_done[bank]),
.wready_o(host_rsp_avail[bank]),
.wdata_i ({rd_err[bank], rd_data[bank]}),
.depth_o (),
.full_o (),
.rvalid_o(host_rsp_vld[bank]),
.rready_i(host_rsp_ack[bank]),
.rdata_o ({host_rsp_err[bank], host_rsp_data[bank]}),
.err_o (rsp_fifo_err[bank])
);
logic host_req;
logic ctrl_req;
assign host_req = host_req_i & (host_bank_sel == bank) & host_rsp_avail[bank];
assign ctrl_req = flash_ctrl_i.req & (ctrl_bank_sel == bank);
assign ecc_addr[bank][BusBankAddrW +: BankW] = bank;
flash_phy_core #(
.SecScrambleEn(SecScrambleEn)
) u_core (
.clk_i,
.rst_ni,
// integrity error is either from host or from controller
.req_i(ctrl_req),
.scramble_en_i(flash_ctrl_i.scramble_en),
.ecc_en_i(flash_ctrl_i.ecc_en),
.he_en_i(flash_ctrl_i.he_en),
// host request must be suppressed if response fifo cannot hold more
// otherwise the flash_phy_core and flash_phy will get out of sync
.host_req_i(host_req),
.host_scramble_en_i(host_scramble_en),
.host_ecc_en_i(host_ecc_en),
.host_addr_i(host_addr_i[0 +: BusBankAddrW]),
.rd_i(flash_ctrl_i.rd),
.prog_i(flash_ctrl_i.prog),
.pg_erase_i(flash_ctrl_i.pg_erase),
.bk_erase_i(flash_ctrl_i.bk_erase),
.erase_suspend_req_i(flash_ctrl_i.erase_suspend),
.part_i(flash_ctrl_i.part),
.info_sel_i(flash_ctrl_i.info_sel),
.addr_i(flash_ctrl_i.addr[0 +: BusBankAddrW]),
.prog_data_i(flash_ctrl_i.prog_data),
.prog_last_i(flash_ctrl_i.prog_last),
.prog_type_i(flash_ctrl_i.prog_type),
.addr_key_i(flash_ctrl_i.addr_key),
.data_key_i(flash_ctrl_i.data_key),
.rand_addr_key_i(flash_ctrl_i.rand_addr_key),
.rand_data_key_i(flash_ctrl_i.rand_data_key),
.rd_buf_en_i(flash_ctrl_i.rd_buf_en),
.host_req_rdy_o(host_req_rdy[bank]),
.host_req_done_o(host_req_done[bank]),
.rd_done_o(rd_done[bank]),
.prog_done_o(prog_done[bank]),
.erase_done_o(erase_done[bank]),
.rd_data_o(rd_data[bank]),
.rd_err_o(rd_err[bank]),
.flash_disable_i(flash_disable[bank]),
.prim_flash_req_o(prim_flash_req[bank]),
.prim_flash_rsp_i(prim_flash_rsp[bank]),
.ecc_single_err_o(ecc_single_err[bank]),
.ecc_addr_o(ecc_addr[bank][BusBankAddrW-1:0]),
.fsm_err_o(fsm_err[bank]),
.prog_intg_err_o(prog_intg_err[bank]),
.relbl_ecc_err_o(relbl_ecc_err[bank]),
.intg_ecc_err_o(intg_ecc_err[bank]),
.spurious_ack_o(spurious_acks[bank]),
.arb_err_o(arb_err[bank]),
.host_gnt_err_o(host_gnt_err[bank]),
.fifo_err_o(core_fifo_err[bank])
);
end // block: gen_flash_banks
// life cycle handling
logic tdo;
lc_ctrl_pkg::lc_tx_t [FlashLcDftLast-1:0] lc_nvm_debug_en;
assign flash_ctrl_o.jtag_rsp.tdo = tdo & (lc_nvm_debug_en[FlashLcTdoSel] == lc_ctrl_pkg::On);
prim_lc_sync #(
.NumCopies(int'(FlashLcDftLast))
) u_lc_nvm_debug_en_sync (
.clk_i,
.rst_ni,
.lc_en_i(lc_nvm_debug_en_i),
.lc_en_o(lc_nvm_debug_en)
);
import lc_ctrl_pkg::lc_tx_test_true_strict;
// if nvm debug is enabled, flash_bist_enable controls entry to flash test mode.
// if nvm debug is disabled, flash_bist_enable is always turned off.
mubi4_t bist_enable_qual;
assign bist_enable_qual = (lc_tx_test_true_strict(lc_nvm_debug_en[FlashBistSel])) ?
flash_bist_enable_i :
MuBi4False;
prim_flash #(
.NumBanks(NumBanks),
.InfosPerBank(InfosPerBank),
.InfoTypes(InfoTypes),
.InfoTypesWidth(InfoTypesWidth),
.PagesPerBank(PagesPerBank),
.WordsPerPage(WordsPerPage),
.DataWidth(flash_phy_pkg::FullDataWidth),
.ModelOnlyReadLatency(ModelOnlyReadLatency),
.ModelOnlyProgLatency(ModelOnlyProgLatency),
.ModelOnlyEraseLatency(ModelOnlyEraseLatency)
) u_flash (
.clk_i,
.rst_ni,
.tl_i,
.tl_o,
.devmode_i(1'b1),
.flash_req_i(prim_flash_req),
.flash_rsp_o(prim_flash_rsp),
.prog_type_avail_o(prog_type_avail),
.init_busy_o(init_busy),
.tck_i(flash_ctrl_i.jtag_req.tck & lc_tx_test_true_strict(lc_nvm_debug_en[FlashLcTckSel])),
.tdi_i(flash_ctrl_i.jtag_req.tdi & lc_tx_test_true_strict(lc_nvm_debug_en[FlashLcTdiSel])),
.tms_i(flash_ctrl_i.jtag_req.tms & lc_tx_test_true_strict(lc_nvm_debug_en[FlashLcTmsSel])),
.tdo_o(tdo),
.bist_enable_i(bist_enable_qual),
.obs_ctrl_i,
.fla_obs_o,
.scanmode_i,
.scan_en_i,
.scan_rst_ni,
.flash_power_ready_h_i,
.flash_power_down_h_i,
.flash_test_mode_a_io,
.flash_test_voltage_h_io,
.flash_err_o(flash_ctrl_o.macro_err),
// There alert signals are forwarded to both flash controller and ast
.fl_alert_src_o(flash_alert_o)
);
logic unused_alert;
assign unused_alert = flash_ctrl_i.alert_trig & flash_ctrl_i.alert_ack;
logic unused_trst_n;
assign unused_trst_n = flash_ctrl_i.jtag_req.trst_n;
assign flash_ctrl_o.jtag_rsp.tdo_oe = 1'b1;
//////////////////////////////////////////////
// Assertions, Assumptions, and Coverpoints //
/////////////////////////////////////////////
// Add some assertions regarding response ordering
endmodule // flash_phy