|  | // 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; | 
|  |  | 
|  | // fixed parameters of flash derived from topgen parameters | 
|  | parameter int DataWidth       = ${cfg['data_width']}; | 
|  | parameter int MetaDataWidth   = ${cfg['metadata_width']}; | 
|  | parameter int InfoTypes       = ${cfg['info_types']}; // How many types of info per bank | 
|  |  | 
|  | // 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 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 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 | 
|  | }; | 
|  |  | 
|  | //////////////////////////// | 
|  | // 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; | 
|  |  | 
|  | // alias for super long reg_pkg typedef | 
|  | typedef flash_ctrl_reg_pkg::flash_ctrl_reg2hw_bank0_info0_page_cfg_mreg_t info_page_cfg_t; | 
|  | typedef flash_ctrl_reg_pkg::flash_ctrl_reg2hw_mp_region_cfg_mreg_t 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; | 
|  |  | 
|  | // 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 = 3; | 
|  | parameter int HwDataRules = 1; | 
|  |  | 
|  | parameter info_page_cfg_t CfgAllowRead = '{ | 
|  | en:          1'b1, | 
|  | rd_en:       1'b1, | 
|  | prog_en:     1'b0, | 
|  | erase_en:    1'b0, | 
|  | scramble_en: 1'b0, | 
|  | ecc_en:      1'b0, // TBD, update to 1 once tb supports ECC | 
|  | he_en:       1'b1 | 
|  | }; | 
|  |  | 
|  | parameter info_page_cfg_t CfgAllowReadProgErase = '{ | 
|  | en:          1'b1, | 
|  | rd_en:       1'b1, | 
|  | prog_en:     1'b1, | 
|  | erase_en:    1'b1, | 
|  | scramble_en: 1'b1, | 
|  | ecc_en:      1'b1, | 
|  | he_en:       1'b1   // HW assumes high endurance | 
|  | }; | 
|  |  | 
|  | parameter info_page_attr_t HwInfoPageAttr[HwInfoRules] = '{ | 
|  | '{ | 
|  | page:  SeedInfoPageSel[CreatorSeedIdx], | 
|  | phase: PhaseSeed, | 
|  | cfg:   CfgAllowRead | 
|  | }, | 
|  |  | 
|  | '{ | 
|  | page:  SeedInfoPageSel[OwnerSeedIdx], | 
|  | phase: PhaseSeed, | 
|  | cfg:   CfgAllowRead | 
|  | }, | 
|  |  | 
|  | '{ | 
|  | page:  SeedInfoPageSel[OwnerSeedIdx], | 
|  | phase: PhaseRma, | 
|  | cfg:   CfgAllowReadProgErase | 
|  | } | 
|  | }; | 
|  |  | 
|  | parameter data_region_attr_t HwDataAttr[HwDataRules] = '{ | 
|  | '{ | 
|  | phase: PhaseRma, | 
|  | cfg:   '{ | 
|  | en:          1'b1, | 
|  | rd_en:       1'b1, | 
|  | prog_en:     1'b1, | 
|  | erase_en:    1'b1, | 
|  | scramble_en: 1'b1, | 
|  | ecc_en:      1'b1, | 
|  | he_en:       1'b1, // HW assumes high endurance | 
|  | base:        '0, | 
|  | size:        '1 | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  |  | 
|  | //////////////////////////// | 
|  | // Design time constants | 
|  | //////////////////////////// | 
|  | parameter flash_key_t RndCnstAddrKeyDefault = | 
|  | 128'h5d707f8a2d01d400928fa691c6a6e0a4; | 
|  | parameter flash_key_t RndCnstDataKeyDefault = | 
|  | 128'h39953618f2ca6f674af39f64975ea1f5; | 
|  |  | 
|  | //////////////////////////// | 
|  | // 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                 ecc_multi_err_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 [BusWidth-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; | 
|  | tlul_pkg::tl_h2d_t    tl_flash_c2p; | 
|  | logic                 alert_trig; | 
|  | logic                 alert_ack; | 
|  | jtag_pkg::jtag_req_t  jtag_req; | 
|  | logic                 intg_err; | 
|  | } 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, | 
|  | ecc_multi_err_en: '0, | 
|  | 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, | 
|  | tl_flash_c2p:  '0, | 
|  | alert_trig:    1'b0, | 
|  | alert_ack:     1'b0, | 
|  | jtag_req:      '0, | 
|  | intg_err:      '0 | 
|  | }; | 
|  |  | 
|  | // 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 [BusWidth-1:0] rd_data; | 
|  | logic                init_busy; | 
|  | tlul_pkg::tl_d2h_t   tl_flash_p2c; | 
|  | logic                flash_err; | 
|  | logic                flash_alert_p; | 
|  | logic                flash_alert_n; | 
|  | logic [NumBanks-1:0] ecc_single_err; | 
|  | logic [NumBanks-1:0] ecc_multi_err; | 
|  | logic [NumBanks-1:0][BusAddrW-1:0] ecc_addr; | 
|  | jtag_pkg::jtag_rsp_t jtag_rsp; | 
|  | logic                intg_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, | 
|  | tl_flash_p2c:       '0, | 
|  | flash_err:          1'b0, | 
|  | flash_alert_p:      1'b0, | 
|  | flash_alert_n:      1'b1, | 
|  | ecc_single_err:     '0, | 
|  | ecc_multi_err:      '0, | 
|  | ecc_addr:           '0, | 
|  | jtag_rsp:           '0, | 
|  | intg_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 = 3; | 
|  | parameter rma_wipe_entry_t RmaWipeEntries[WipeEntries] = '{ | 
|  | '{ | 
|  | bank: SeedBank, | 
|  | part: FlashPartInfo, | 
|  | info_sel: SeedInfoSel, | 
|  | start_page: {1'b0, OwnerInfoPage}, | 
|  | 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; | 
|  |  | 
|  | // 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 | 
|  |  | 
|  |  | 
|  | endpackage : flash_ctrl_pkg |