blob: 0f72bf5b5d50f1d3e893084426747b4d8490ed93 [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 Controller module.
//
package flash_ctrl_pkg;
// design parameters that can be altered through topgen
parameter int unsigned NumBanks = flash_ctrl_reg_pkg::RegNumBanks;
parameter int unsigned PagesPerBank = flash_ctrl_reg_pkg::RegPagesPerBank;
parameter int unsigned BusPgmResBytes = flash_ctrl_reg_pkg::RegBusPgmResBytes;
// How many types of info per bank
parameter int InfoTypes = flash_ctrl_reg_pkg::NumInfoTypes;
// fixed parameters of flash derived from topgen parameters
parameter int DataWidth = ${cfg.data_width};
parameter int MetaDataWidth = ${cfg.metadata_width};
// The following hard-wired values are there to work-around verilator.
// For some reason if the values are assigned through parameters verilator thinks
// they are not constant
parameter int InfoTypeSize [InfoTypes] = '{
% for type in range(cfg.info_types):
${cfg.infos_per_bank[type]}${"," if not loop.last else ""}
% endfor
};
parameter int InfosPerBank = max_info_pages('{
% for type in range(cfg.info_types):
${cfg.infos_per_bank[type]}${"," if not loop.last else ""}
% endfor
});
parameter int WordsPerPage = ${cfg.words_per_page}; // Number of flash words per page
parameter int BusWidth = top_pkg::TL_DW;
parameter int BusIntgWidth = tlul_pkg::DataIntgWidth;
parameter int BusFullWidth = BusWidth + BusIntgWidth;
parameter int MpRegions = 8; // flash controller protection regions
//parameter int FifoDepth = 16; // rd / prog fifos
parameter int InfoTypesWidth = prim_util_pkg::vbits(InfoTypes);
// flash phy parameters
parameter int DataByteWidth = prim_util_pkg::vbits(DataWidth / 8);
parameter int BankW = prim_util_pkg::vbits(NumBanks);
parameter int InfoPageW = prim_util_pkg::vbits(InfosPerBank);
parameter int PageW = prim_util_pkg::vbits(PagesPerBank);
parameter int WordW = prim_util_pkg::vbits(WordsPerPage);
parameter int AddrW = BankW + PageW + WordW; // all flash range
parameter int BankAddrW = PageW + WordW; // 1 bank of flash range
parameter int AllPagesW = BankW + PageW;
// flash ctrl / bus parameters
// flash / bus width may be different from actual flash word width
parameter int BusBytes = BusWidth / 8;
parameter int BusByteWidth = prim_util_pkg::vbits(BusBytes);
parameter int WidthMultiple = DataWidth / BusWidth;
// Number of bus words that can be programmed at once
parameter int BusPgmRes = BusPgmResBytes / BusBytes;
parameter int BusPgmResWidth = prim_util_pkg::vbits(BusPgmRes);
parameter int BusWordsPerPage = WordsPerPage * WidthMultiple;
parameter int BusWordW = prim_util_pkg::vbits(BusWordsPerPage);
parameter int BusAddrW = BankW + PageW + BusWordW;
parameter int BusAddrByteW = BusAddrW + BusByteWidth;
parameter int BusBankAddrW = PageW + BusWordW;
parameter int PhyAddrStart = BusWordW - WordW;
// fifo parameters
//parameter int FifoDepthW = prim_util_pkg::vbits(FifoDepth+1);
// The end address in bus words for each kind of partition in each bank
parameter logic [PageW-1:0] DataPartitionEndAddr = PageW'(PagesPerBank - 1);
//parameter logic [PageW-1:0] InfoPartitionEndAddr [InfoTypes] = '{
% for type in range((cfg.info_types)):
// ${cfg.infos_per_bank[type]-1}${"," if not loop.last else ""}
% endfor
//};
parameter logic [PageW-1:0] InfoPartitionEndAddr [InfoTypes] = '{
% for type in range((cfg.info_types)):
PageW'(InfoTypeSize[${type}] - 1)${"," if not loop.last else ""}
% endfor
};
// Flash Disable usage
typedef enum logic [3:0] {
PhyDisableIdx,
ArbFsmDisableIdx,
LcMgrDisableIdx,
MpDisableIdx,
HostDisableIdx,
IFetchDisableIdx,
RdFifoIdx,
ProgFifoIdx,
FlashDisableLast
} flash_disable_pos_e;
////////////////////////////
// All memory protection, seed related parameters
// Those related for seed pages should be template candidates
////////////////////////////
// parameters for connected components
parameter int SeedWidth = 256;
parameter int KeyWidth = 128;
parameter int EdnWidth = edn_pkg::ENDPOINT_BUS_WIDTH;
typedef logic [KeyWidth-1:0] flash_key_t;
// Default Lfsr configurations
// These LFSR parameters have been generated with
// $ util/design/gen-lfsr-seed.py --width 32 --seed 1274809145 --prefix ""
parameter int LfsrWidth = 32;
typedef logic [LfsrWidth-1:0] lfsr_seed_t;
typedef logic [LfsrWidth-1:0][$clog2(LfsrWidth)-1:0] lfsr_perm_t;
parameter lfsr_seed_t RndCnstLfsrSeedDefault = 32'ha8cee782;
parameter lfsr_perm_t RndCnstLfsrPermDefault = {
160'hd60bc7d86445da9347e0ccdd05b281df95238bb5
};
// These LFSR parameters have been generated with
// $ util/design/gen-lfsr-seed.py --width 64 --seed 691876113 --prefix ""
// lcmgr phase enum
typedef enum logic [1:0] {
PhaseSeed,
PhaseRma,
PhaseNone,
PhaseInvalid
} flash_lcmgr_phase_e;
import flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t;
import flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_region_mreg_t;
import flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_region_cfg_mreg_t;
import flash_ctrl_reg_pkg::flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t;
import flash_ctrl_reg_pkg::flash_ctrl_reg2hw_default_region_reg_t;
typedef flash_ctrl_reg2hw_mp_bank_cfg_shadowed_mreg_t sw_bank_cfg_t;
typedef flash_ctrl_reg2hw_mp_region_mreg_t sw_region_t;
typedef flash_ctrl_reg2hw_mp_region_cfg_mreg_t sw_region_cfg_t;
typedef flash_ctrl_reg2hw_default_region_reg_t sw_default_cfg_t;
typedef flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t sw_info_cfg_t;
// alias for super long reg_pkg typedef
typedef struct packed {
logic q;
} bank_cfg_t;
import prim_mubi_pkg::mubi4_t;
import prim_mubi_pkg::MuBi4True;
import prim_mubi_pkg::MuBi4False;
// This is identical to the reg structures but do not have err_updates / storage
typedef struct packed {
mubi4_t en;
mubi4_t rd_en;
mubi4_t prog_en;
mubi4_t erase_en;
mubi4_t scramble_en;
mubi4_t ecc_en;
mubi4_t he_en;
} info_page_cfg_t;
// This is identical to the reg structures but do not have err_updates / storage
typedef struct packed {
mubi4_t en;
mubi4_t rd_en;
mubi4_t prog_en;
mubi4_t erase_en;
mubi4_t scramble_en;
mubi4_t ecc_en;
mubi4_t he_en;
logic [8:0] base;
logic [9:0] size;
} mp_region_cfg_t;
// memory protection specific structs
typedef struct packed {
logic [InfoTypesWidth-1:0] sel;
logic [AllPagesW-1:0] addr;
} page_addr_t;
typedef struct packed {
page_addr_t page;
flash_lcmgr_phase_e phase;
info_page_cfg_t cfg;
} info_page_attr_t;
typedef struct packed {
flash_lcmgr_phase_e phase;
mp_region_cfg_t cfg;
} data_region_attr_t;
// flash life cycle / key manager management constants
// One page for creator seeds
// One page for owner seeds
// One page for isolated flash page
parameter int NumSeeds = 2;
parameter bit [BankW-1:0] SeedBank = 0;
parameter bit [InfoTypesWidth-1:0] SeedInfoSel = 0;
parameter bit [0:0] CreatorSeedIdx = 0;
parameter bit [0:0] OwnerSeedIdx = 1;
parameter bit [PageW-1:0] CreatorInfoPage = 1;
parameter bit [PageW-1:0] OwnerInfoPage = 2;
parameter bit [PageW-1:0] IsolatedInfoPage = 3;
parameter int TotalSeedWidth = SeedWidth * NumSeeds;
typedef logic [TotalSeedWidth-1:0] all_seeds_t;
// which page of which info type of which bank for seed selection
parameter page_addr_t SeedInfoPageSel [NumSeeds] = '{
'{
sel: SeedInfoSel,
addr: {SeedBank, CreatorInfoPage}
},
'{
sel: SeedInfoSel,
addr: {SeedBank, OwnerInfoPage}
}
};
// which page of which info type of which bank for isolated partition
parameter page_addr_t IsolatedPageSel = '{
sel: SeedInfoSel,
addr: {SeedBank, IsolatedInfoPage}
};
// hardware interface memory protection rules
parameter int HwInfoRules = 5;
parameter int HwDataRules = 1;
parameter info_page_cfg_t CfgAllowRead = '{
en: MuBi4True,
rd_en: MuBi4True,
prog_en: MuBi4False,
erase_en: MuBi4False,
scramble_en: MuBi4True,
ecc_en: MuBi4True,
he_en: MuBi4True
};
parameter info_page_cfg_t CfgAllowReadProgErase = '{
en: MuBi4True,
rd_en: MuBi4True,
prog_en: MuBi4True,
erase_en: MuBi4True,
scramble_en: MuBi4True,
ecc_en: MuBi4True,
he_en: MuBi4True // HW assumes high endurance
};
parameter info_page_cfg_t CfgInfoDisable = '{
en: MuBi4False,
rd_en: MuBi4False,
prog_en: MuBi4False,
erase_en: MuBi4False,
scramble_en: MuBi4False,
ecc_en: MuBi4False,
he_en: MuBi4False
};
parameter info_page_attr_t HwInfoPageAttr[HwInfoRules] = '{
'{
page: SeedInfoPageSel[CreatorSeedIdx],
phase: PhaseSeed,
cfg: CfgAllowRead
},
'{
page: SeedInfoPageSel[OwnerSeedIdx],
phase: PhaseSeed,
cfg: CfgAllowRead
},
'{
page: SeedInfoPageSel[CreatorSeedIdx],
phase: PhaseRma,
cfg: CfgAllowReadProgErase
},
'{
page: SeedInfoPageSel[OwnerSeedIdx],
phase: PhaseRma,
cfg: CfgAllowReadProgErase
},
'{
page: IsolatedPageSel,
phase: PhaseRma,
cfg: CfgAllowReadProgErase
}
};
parameter data_region_attr_t HwDataAttr[HwDataRules] = '{
'{
phase: PhaseRma,
cfg: '{
en: MuBi4True,
rd_en: MuBi4True,
prog_en: MuBi4True,
erase_en: MuBi4True,
scramble_en: MuBi4True,
ecc_en: MuBi4True,
he_en: MuBi4True, // HW assumes high endurance
base: '0,
size: NumBanks * PagesPerBank
}
}
};
////////////////////////////
// Design time constants
////////////////////////////
parameter flash_key_t RndCnstAddrKeyDefault =
128'h5d707f8a2d01d400928fa691c6a6e0a4;
parameter flash_key_t RndCnstDataKeyDefault =
128'h39953618f2ca6f674af39f64975ea1f5;
parameter all_seeds_t RndCnstAllSeedsDefault = {
256'h3528874c0d9e481ead4d240eb6238a2c6218896f5315edb5ccefe029a6d04091,
256'h9cde77e25a313a76984ab0ebf990983432b03b48186dcd556565fe721b447477
};
////////////////////////////
// Flash operation related enums
////////////////////////////
// Flash Operations Supported
typedef enum logic [1:0] {
FlashOpRead = 2'h0,
FlashOpProgram = 2'h1,
FlashOpErase = 2'h2,
FlashOpInvalid = 2'h3
} flash_op_e;
// Flash Program Operations Supported
typedef enum logic {
FlashProgNormal = 0,
FlashProgRepair = 1
} flash_prog_e;
parameter int ProgTypes = 2;
// Flash Erase Operations Supported
typedef enum logic {
FlashErasePage = 0,
FlashEraseBank = 1
} flash_erase_e;
// Flash function select
typedef enum logic [1:0] {
NoneSel,
SwSel,
HwSel
} flash_sel_e;
// Flash tlul to fifo direction
typedef enum logic {
WriteDir = 1'b0,
ReadDir = 1'b1
} flash_flfo_dir_e;
// Flash partition type
typedef enum logic {
FlashPartData = 1'b0,
FlashPartInfo = 1'b1
} flash_part_e;
// Flash controller to memory
typedef struct packed {
logic req;
logic scramble_en;
logic ecc_en;
logic he_en;
logic rd_buf_en;
logic rd;
logic prog;
logic pg_erase;
logic bk_erase;
logic erase_suspend;
flash_part_e part;
logic [InfoTypesWidth-1:0] info_sel;
logic [BusAddrW-1:0] addr;
logic [BusFullWidth-1:0] prog_data;
logic prog_last;
flash_prog_e prog_type;
mp_region_cfg_t [MpRegions:0] region_cfgs;
logic [KeyWidth-1:0] addr_key;
logic [KeyWidth-1:0] data_key;
logic [KeyWidth-1:0] rand_addr_key;
logic [KeyWidth-1:0] rand_data_key;
logic alert_trig;
logic alert_ack;
jtag_pkg::jtag_req_t jtag_req;
prim_mubi_pkg::mubi4_t flash_disable;
} flash_req_t;
// default value of flash_req_t (for dangling ports)
parameter flash_req_t FLASH_REQ_DEFAULT = '{
req: '0,
scramble_en: '0,
ecc_en: '0,
he_en: '0,
rd_buf_en: 1'b0,
rd: '0,
prog: '0,
pg_erase: '0,
bk_erase: '0,
erase_suspend: '0,
part: FlashPartData,
info_sel: '0,
addr: '0,
prog_data: '0,
prog_last: '0,
prog_type: FlashProgNormal,
region_cfgs: '0,
addr_key: RndCnstAddrKeyDefault,
data_key: RndCnstDataKeyDefault,
rand_addr_key: '0,
rand_data_key: '0,
alert_trig: 1'b0,
alert_ack: 1'b0,
jtag_req: '0,
flash_disable: prim_mubi_pkg::MuBi4False
};
// memory to flash controller
typedef struct packed {
logic [ProgTypes-1:0] prog_type_avail;
logic rd_done;
logic prog_done;
logic erase_done;
logic rd_err;
logic [BusFullWidth-1:0] rd_data;
logic init_busy;
logic macro_err;
logic [NumBanks-1:0] ecc_single_err;
logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr;
jtag_pkg::jtag_rsp_t jtag_rsp;
logic prog_intg_err;
logic storage_relbl_err;
logic storage_intg_err;
logic fsm_err;
logic spurious_ack;
logic arb_err;
logic host_gnt_err;
logic fifo_err;
} flash_rsp_t;
// default value of flash_rsp_t (for dangling ports)
parameter flash_rsp_t FLASH_RSP_DEFAULT = '{
prog_type_avail: {ProgTypes{1'b1}},
rd_done: 1'b0,
prog_done: 1'b0,
erase_done: 1'b0,
rd_err: '0,
rd_data: '0,
init_busy: 1'b0,
macro_err: 1'b0,
ecc_single_err: '0,
ecc_addr: '0,
jtag_rsp: '0,
prog_intg_err: '0,
storage_relbl_err: '0,
storage_intg_err: '0,
fsm_err: '0,
spurious_ack: '0,
arb_err: '0,
host_gnt_err: '0,
fifo_err: '0
};
// RMA entries
typedef struct packed {
logic [BankW-1:0] bank;
flash_part_e part;
logic [InfoTypesWidth-1:0] info_sel;
logic [PageW:0] start_page;
logic [PageW:0] num_pages;
} rma_wipe_entry_t;
// entries to be wiped
parameter int WipeEntries = 5;
parameter rma_wipe_entry_t RmaWipeEntries[WipeEntries] = '{
'{
bank: SeedBank,
part: FlashPartInfo,
info_sel: SeedInfoSel,
start_page: {1'b0, CreatorInfoPage},
num_pages: 1
},
'{
bank: SeedBank,
part: FlashPartInfo,
info_sel: SeedInfoSel,
start_page: {1'b0, OwnerInfoPage},
num_pages: 1
},
'{
bank: SeedBank,
part: FlashPartInfo,
info_sel: SeedInfoSel,
start_page: {1'b0, IsolatedInfoPage},
num_pages: 1
},
'{
bank: 0,
part: FlashPartData,
info_sel: 0,
start_page: 0,
num_pages: (PageW + 1)'(PagesPerBank)
},
'{
bank: 1,
part: FlashPartData,
info_sel: 0,
start_page: 0,
num_pages: (PageW + 1)'(PagesPerBank)
}
};
// flash_ctrl to keymgr
typedef struct packed {
logic [NumSeeds-1:0][SeedWidth-1:0] seeds;
} keymgr_flash_t;
parameter keymgr_flash_t KEYMGR_FLASH_DEFAULT = '{
seeds: '{
256'h9152e32c9380a4bcc3e0ab263581e6b0e8825186e1e445631646e8bef8c45d47,
256'hfa365df52da48cd752fb3a026a8e608f0098cfe5fa9810494829d0cd9479eb78
}
};
// dft_en jtag selection
typedef enum logic [2:0] {
FlashLcTckSel,
FlashLcTdiSel,
FlashLcTmsSel,
FlashLcTdoSel,
FlashBistSel,
FlashLcDftLast
} flash_lc_jtag_e;
// Error bit positioning
typedef struct packed {
logic invalid_op_err;
logic oob_err;
logic mp_err;
logic rd_err;
logic prog_err;
logic prog_win_err;
logic prog_type_err;
} flash_ctrl_err_t;
// interrupt bit positioning
typedef enum logic[2:0] {
ProgEmpty,
ProgLvl,
RdFull,
RdLvl,
OpDone,
CorrErr,
LastIntrIdx
} flash_ctrl_intr_e;
// find the max number pages among info types
function automatic integer max_info_pages(int infos[InfoTypes]);
int current_max = 0;
for (int i = 0; i < InfoTypes; i++) begin
if (infos[i] > current_max) begin
current_max = infos[i];
end
end
return current_max;
endfunction // max_info_banks
// RMA control FSM encoding
// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 5 -m 7 -n 10 \
// -s 3319803877 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: --
// 4: --
// 5: |||||||||||||||||||| (47.62%)
// 6: |||||||||||||||| (38.10%)
// 7: |||| (9.52%)
// 8: || (4.76%)
// 9: --
// 10: --
//
// Minimum Hamming distance: 5
// Maximum Hamming distance: 8
// Minimum Hamming weight: 3
// Maximum Hamming weight: 6
//
localparam int RmaStateWidth = 11;
typedef enum logic [RmaStateWidth-1:0] {
StRmaIdle = 11'b11110001010,
StRmaPageSel = 11'b10111100111,
StRmaErase = 11'b11000010111,
StRmaEraseWait = 11'b01010100110,
StRmaWordSel = 11'b00010011001,
StRmaProgram = 11'b11011111101,
StRmaProgramWait = 11'b00111110000,
StRmaRdVerify = 11'b00101001100,
StRmaDisabled = 11'b01001011010,
StRmaInvalid = 11'b10100111011
} rma_state_e;
// find the max number pages among info types
function automatic info_page_cfg_t info_cfg_qual(info_page_cfg_t in_cfg,
info_page_cfg_t qual_cfg);
info_page_cfg_t out_cfg;
out_cfg = '{
en: prim_mubi_pkg::mubi4_and_hi(in_cfg.en, qual_cfg.en),
rd_en: prim_mubi_pkg::mubi4_and_hi(in_cfg.rd_en, qual_cfg.rd_en),
prog_en: prim_mubi_pkg::mubi4_and_hi(in_cfg.prog_en, qual_cfg.prog_en),
erase_en: prim_mubi_pkg::mubi4_and_hi(in_cfg.erase_en, qual_cfg.erase_en),
scramble_en: prim_mubi_pkg::mubi4_and_hi(in_cfg.scramble_en, qual_cfg.scramble_en),
ecc_en: prim_mubi_pkg::mubi4_and_hi(in_cfg.ecc_en, qual_cfg.ecc_en),
he_en : prim_mubi_pkg::mubi4_and_hi(in_cfg.he_en, qual_cfg.he_en)
};
return out_cfg;
endfunction // max_info_banks
endpackage : flash_ctrl_pkg