| // 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 |