blob: 5fca6c61d3b8e5dc2109bc7f57cce8c3a251ed09 [file] [log] [blame]
Timothy Chen5cdde152020-08-14 20:46:21 -07001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4//
5// Flash Controller for life cycle / key management handling
6//
7
Timothy Chenf52a4612020-12-04 20:37:49 -08008module flash_ctrl_lcmgr import flash_ctrl_pkg::*; #(
9 parameter flash_key_t RndCnstAddrKey = RndCnstAddrKeyDefault,
10 parameter flash_key_t RndCnstDataKey = RndCnstDataKeyDefault
11) (
Timothy Chen5cdde152020-08-14 20:46:21 -070012 input clk_i,
13 input rst_ni,
Timothy Chenf52a4612020-12-04 20:37:49 -080014 input clk_otp_i,
15 input rst_otp_ni,
Timothy Chen5cdde152020-08-14 20:46:21 -070016
Timothy Chen04834fd2020-09-11 14:58:32 -070017 // initialization command
18 input init_i,
19
20 // only access seeds when provisioned
21 input provision_en_i,
22
Timothy Chen5cdde152020-08-14 20:46:21 -070023 // interface to ctrl arb control ports
24 output flash_ctrl_reg_pkg::flash_ctrl_reg2hw_control_reg_t ctrl_o,
25 output logic req_o,
Timothy Chen2df95612020-08-31 15:29:12 -070026 output logic [top_pkg::TL_AW-1:0] addr_o,
Timothy Chen5cdde152020-08-14 20:46:21 -070027 input done_i,
28 input err_i,
29
30 // interface to ctrl_arb data ports
31 output logic rready_o,
32 input rvalid_i,
Timothy Chend39402a2020-12-15 20:34:09 -080033 output logic wvalid_o,
34 input wready_i,
Timothy Chen5cdde152020-08-14 20:46:21 -070035
36 // direct form rd_fifo
37 input [BusWidth-1:0] rdata_i,
38
Timothy Chend39402a2020-12-15 20:34:09 -080039 // direct to wr_fifo
40 output logic [BusWidth-1:0] wdata_o,
41
Timothy Chen5cdde152020-08-14 20:46:21 -070042 // external rma request
Timothy Chen04834fd2020-09-11 14:58:32 -070043 // This should be simplified to just multi-bit request and multi-bit response
Timothy Chend39402a2020-12-15 20:34:09 -080044 input lc_ctrl_pkg::lc_tx_t rma_req_i,
45 output lc_ctrl_pkg::lc_tx_t rma_ack_o,
Timothy Chen5cdde152020-08-14 20:46:21 -070046
Timothy Chen5cdde152020-08-14 20:46:21 -070047 // seeds to the outside world,
48 output logic [NumSeeds-1:0][SeedWidth-1:0] seeds_o,
49
Timothy Chen8204f1d2020-09-02 19:05:39 -070050 // indicate to memory protection what phase the hw interface is in
51 output flash_lcmgr_phase_e phase_o,
52
53 // error status to registers
54 output logic seed_err_o,
55
Timothy Chen6b241b32020-11-13 15:15:45 -080056 // enable read buffer in flash_phy
57 output logic rd_buf_en_o,
58
Timothy Chenf52a4612020-12-04 20:37:49 -080059 // request otp keys
60 output otp_ctrl_pkg::flash_otp_key_req_t otp_key_req_o,
61 input otp_ctrl_pkg::flash_otp_key_rsp_t otp_key_rsp_i,
62 output flash_key_t addr_key_o,
63 output flash_key_t data_key_o,
Timothy Chene1e0fd62021-04-07 16:13:28 -070064 output flash_key_t rand_addr_key_o,
65 output flash_key_t rand_data_key_o,
Timothy Chenf52a4612020-12-04 20:37:49 -080066
Timothy Chenaeffadc2020-12-11 15:03:07 -080067 // entropy interface
68 output logic edn_req_o,
69 input edn_ack_i,
70 output logic lfsr_en_o,
71 input [BusWidth-1:0] rand_i,
72
Timothy Chen5cdde152020-08-14 20:46:21 -070073 // init ongoing
74 output logic init_busy_o
75);
76
77 // total number of pages to be wiped during RMA entry
Rupert Swarbrick723c05e2021-03-30 09:26:17 +010078 localparam int unsigned WipeIdxWidth = prim_util_pkg::vbits(WipeEntries);
79 localparam int unsigned MaxWipeEntry = WipeEntries - 1;
Timothy Chen5cdde152020-08-14 20:46:21 -070080
81 // seed related local params
Rupert Swarbrick723c05e2021-03-30 09:26:17 +010082 localparam int unsigned SeedReads = SeedWidth / BusWidth;
83 localparam int unsigned SeedRdsWidth = $clog2(SeedReads);
84 localparam int unsigned SeedCntWidth = $clog2(NumSeeds+1);
85 localparam int unsigned NumSeedWidth = $clog2(NumSeeds);
Timothy Chen5cdde152020-08-14 20:46:21 -070086
87 // the various seed outputs
88 logic [NumSeeds-1:0][SeedReads-1:0][BusWidth-1:0] seeds_q;
89
Timothy Chen5cdde152020-08-14 20:46:21 -070090 // progress through and read out the various pieces of content
91 // This FSM should become sparse, especially for StRmaRsp
92 typedef enum logic [3:0] {
Timothy Chen04834fd2020-09-11 14:58:32 -070093 StIdle,
Timothy Chenf52a4612020-12-04 20:37:49 -080094 StReqAddrKey,
95 StReqDataKey,
Timothy Chen5cdde152020-08-14 20:46:21 -070096 StReadSeeds,
97 StWait,
Timothy Chenaeffadc2020-12-11 15:03:07 -080098 StEntropyReseed,
Timothy Chend39402a2020-12-15 20:34:09 -080099 StRmaWipe,
Timothy Chen8204f1d2020-09-02 19:05:39 -0700100 StRmaRsp,
101 StInvalid
Timothy Chen5cdde152020-08-14 20:46:21 -0700102 } state_e;
103
104 state_e state_q, state_d;
Timothy Chend39402a2020-12-15 20:34:09 -0800105 lc_ctrl_pkg::lc_tx_t err_sts;
106 logic err_sts_set;
107 lc_ctrl_pkg::lc_tx_t rma_ack_d, rma_ack_q;
Timothy Chen5cdde152020-08-14 20:46:21 -0700108 logic validate_q, validate_d;
109 logic [SeedCntWidth-1:0] seed_cnt_q;
Timothy Chend39402a2020-12-15 20:34:09 -0800110 logic [SeedRdsWidth-1:0] addr_cnt_q;
Timothy Chen5cdde152020-08-14 20:46:21 -0700111 logic seed_cnt_en, seed_cnt_clr;
112 logic addr_cnt_en, addr_cnt_clr;
Timothy Chend39402a2020-12-15 20:34:09 -0800113 logic rma_wipe_req, rma_wipe_done;
114 logic [WipeIdxWidth-1:0] rma_wipe_idx;
115 logic rma_wipe_idx_incr;
Timothy Chen8204f1d2020-09-02 19:05:39 -0700116 flash_lcmgr_phase_e phase;
Timothy Chen5cdde152020-08-14 20:46:21 -0700117 logic seed_phase;
118 logic rma_phase;
119
Timothy Chen8204f1d2020-09-02 19:05:39 -0700120 assign seed_phase = phase == PhaseSeed;
121 assign rma_phase = phase == PhaseRma;
122
Timothy Chen5cdde152020-08-14 20:46:21 -0700123 always_ff @(posedge clk_i or negedge rst_ni) begin
124 if (!rst_ni) begin
Timothy Chen04834fd2020-09-11 14:58:32 -0700125 state_q <= StIdle;
Timothy Chend39402a2020-12-15 20:34:09 -0800126 rma_ack_q <= lc_ctrl_pkg::Off;
Timothy Chen5cdde152020-08-14 20:46:21 -0700127 validate_q <= 1'b0;
128 end else begin
129 state_q <= state_d;
Timothy Chend39402a2020-12-15 20:34:09 -0800130 rma_ack_q <= rma_ack_d;
Timothy Chen5cdde152020-08-14 20:46:21 -0700131 validate_q <= validate_d;
132 end
133 end
134
135 // seed cnt tracks which seed round we are handling at the moment
136 always_ff @(posedge clk_i or negedge rst_ni) begin
137 if (!rst_ni) begin
138 seed_cnt_q <= '0;
139 end else if (seed_cnt_clr) begin
140 seed_cnt_q <= '0;
141 end else if (seed_cnt_en) begin
142 seed_cnt_q <= seed_cnt_q + 1'b1;
143 end
144 end
145
146 // addr cnt tracks how far we are in an address looop
147 always_ff @(posedge clk_i or negedge rst_ni) begin
148 if (!rst_ni) begin
149 addr_cnt_q <= '0;
150 end else if (addr_cnt_clr) begin
151 addr_cnt_q <= '0;
152 end else if (addr_cnt_en) begin
153 addr_cnt_q <= addr_cnt_q + 1'b1;
154 end
155 end
156
157 // capture the seed values
158 logic [SeedRdsWidth-1:0] rd_idx;
159 logic [NumSeedWidth-1:0] seed_idx;
160 assign rd_idx = addr_cnt_q[SeedRdsWidth-1:0];
161 assign seed_idx = seed_cnt_q[NumSeedWidth-1:0];
162 always_ff @(posedge clk_i) begin
163 // validate current value
164 if (seed_phase && validate_q && rvalid_i) begin
165 seeds_q[seed_idx][rd_idx] <= seeds_q[seed_idx][rd_idx] &
166 rdata_i;
167 end else if (seed_phase && rvalid_i) begin
168 seeds_q[seed_idx][rd_idx] <= rdata_i;
169 end
170 end
171
Timothy Chen782f27a2020-09-17 22:57:57 -0700172 page_addr_t seed_page;
173 logic [InfoTypesWidth-1:0] seed_info_sel;
Timothy Chen5cdde152020-08-14 20:46:21 -0700174 logic [BusAddrW-1:0] seed_page_addr;
Timothy Chen782f27a2020-09-17 22:57:57 -0700175 assign seed_page = SeedInfoPageSel[seed_idx];
176 assign seed_info_sel = seed_page.sel;
177 assign seed_page_addr = BusAddrW'({seed_page.addr, BusWordW'(0)});
Timothy Chen5cdde152020-08-14 20:46:21 -0700178
Timothy Chen5cdde152020-08-14 20:46:21 -0700179 logic start;
180 flash_op_e op;
Timothy Chen103b4cb2020-09-12 15:31:37 -0700181 flash_prog_e prog_type;
Timothy Chen5cdde152020-08-14 20:46:21 -0700182 flash_erase_e erase_type;
183 flash_part_e part_sel;
Timothy Chen782f27a2020-09-17 22:57:57 -0700184 logic [InfoTypesWidth-1:0] info_sel;
Timothy Chen5cdde152020-08-14 20:46:21 -0700185 logic [11:0] num_words;
186 logic [BusAddrW-1:0] addr;
Timothy Chen5cdde152020-08-14 20:46:21 -0700187
Timothy Chen103b4cb2020-09-12 15:31:37 -0700188 assign prog_type = FlashProgNormal;
Timothy Chen5cdde152020-08-14 20:46:21 -0700189 assign erase_type = FlashErasePage;
190 // seed phase is always read
191 // rma phase is erase unless we are validating
Timothy Chend39402a2020-12-15 20:34:09 -0800192 assign op = FlashOpRead;
Timothy Chen5cdde152020-08-14 20:46:21 -0700193
Timothy Chena49dc7b2020-09-15 17:02:03 -0700194 // synchronize inputs
195 logic init_q;
Cindy Chen39b14342021-01-29 16:25:24 -0800196 lc_ctrl_pkg::lc_tx_t [0:0] rma_req;
Timothy Chena49dc7b2020-09-15 17:02:03 -0700197
198 prim_flop_2sync #(
199 .Width(1),
200 .ResetValue(0)
201 ) u_sync_flash_init (
202 .clk_i,
203 .rst_ni,
204 .d_i(init_i),
205 .q_o(init_q)
206 );
207
Timothy Chend39402a2020-12-15 20:34:09 -0800208 prim_lc_sync #(
209 .NumCopies(1)
210 ) u_sync_rma_req (
211 .clk_i,
212 .rst_ni,
213 .lc_en_i(rma_req_i),
214 .lc_en_o(rma_req)
215 );
216
Timothy Chenf52a4612020-12-04 20:37:49 -0800217 logic addr_key_req_d;
218 logic addr_key_ack_q;
219 logic data_key_req_d;
220 logic data_key_ack_q;
221
222 // req/ack to otp
223 prim_sync_reqack u_addr_sync_reqack (
224 .clk_src_i(clk_i),
225 .rst_src_ni(rst_ni),
226 .clk_dst_i(clk_otp_i),
227 .rst_dst_ni(rst_otp_ni),
228 .src_req_i(addr_key_req_d),
229 .src_ack_o(addr_key_ack_q),
230 .dst_req_o(otp_key_req_o.addr_req),
231 .dst_ack_i(otp_key_rsp_i.addr_ack)
232 );
233
234 // req/ack to otp
235 prim_sync_reqack u_data_sync_reqack (
236 .clk_src_i(clk_i),
237 .rst_src_ni(rst_ni),
238 .clk_dst_i(clk_otp_i),
239 .rst_dst_ni(rst_otp_ni),
240 .src_req_i(data_key_req_d),
241 .src_ack_o(data_key_ack_q),
242 .dst_req_o(otp_key_req_o.data_req),
243 .dst_ack_i(otp_key_rsp_i.data_ack)
244 );
245
246 always_ff @(posedge clk_i or negedge rst_ni) begin
247 if (!rst_ni) begin
248 addr_key_o <= RndCnstAddrKey;
249 data_key_o <= RndCnstDataKey;
250 end else begin
251 if (addr_key_req_d && addr_key_ack_q) begin
252 addr_key_o <= flash_key_t'(otp_key_rsp_i.key);
Timothy Chene1e0fd62021-04-07 16:13:28 -0700253 rand_addr_key_o <= flash_key_t'(otp_key_rsp_i.rand_key);
Timothy Chenf52a4612020-12-04 20:37:49 -0800254 end
255
256 if (data_key_req_d && data_key_ack_q) begin
257 data_key_o <= flash_key_t'(otp_key_rsp_i.key);
Timothy Chene1e0fd62021-04-07 16:13:28 -0700258 rand_data_key_o <= flash_key_t'(otp_key_rsp_i.rand_key);
Timothy Chenf52a4612020-12-04 20:37:49 -0800259 end
260 end
261 end
262
Timothy Chend39402a2020-12-15 20:34:09 -0800263
264 ///////////////////////////////
265 // Hardware Interface FSM
266 // TODO: Merge the read/verify mechanism with RMA later
267 ///////////////////////////////
Timothy Chen5cdde152020-08-14 20:46:21 -0700268 always_comb begin
269
270 // phases of the hardware interface
Timothy Chen8204f1d2020-09-02 19:05:39 -0700271 phase = PhaseNone;
Timothy Chen5cdde152020-08-14 20:46:21 -0700272
273 // timer controls
274 seed_cnt_en = 1'b0;
275 seed_cnt_clr = 1'b0;
276 addr_cnt_en = 1'b0;
277 addr_cnt_clr = 1'b0;
278
279 // flash ctrrl arb controls
280 start = 1'b0;
281 addr = '0;
282 part_sel = FlashPartInfo;
Timothy Chen782f27a2020-09-17 22:57:57 -0700283 info_sel = 0;
Rupert Swarbrick723c05e2021-03-30 09:26:17 +0100284 num_words = SeedReads[11:0] - 12'd1;
Timothy Chen5cdde152020-08-14 20:46:21 -0700285
Timothy Chen8204f1d2020-09-02 19:05:39 -0700286 // seed status
287 seed_err_o = 1'b0;
288
Timothy Chen5cdde152020-08-14 20:46:21 -0700289 state_d = state_q;
Timothy Chen5e856072020-12-17 14:48:06 -0800290 rma_ack_d = lc_ctrl_pkg::Off;
Timothy Chen5cdde152020-08-14 20:46:21 -0700291 validate_d = validate_q;
292
Timothy Chen6b241b32020-11-13 15:15:45 -0800293 // read buffer enable
294 rd_buf_en_o = 1'b0;
295
Timothy Chenf52a4612020-12-04 20:37:49 -0800296 addr_key_req_d = 1'b0;
297 data_key_req_d = 1'b0;
298
Timothy Chenaeffadc2020-12-11 15:03:07 -0800299 // entropy handling
300 edn_req_o = 1'b0;
301 lfsr_en_o = 1'b0;
302
Timothy Chen5e856072020-12-17 14:48:06 -0800303 // rma related
Timothy Chend39402a2020-12-15 20:34:09 -0800304 rma_wipe_req = 1'b0;
305 rma_wipe_idx_incr = 1'b0;
306
Timothy Chen5cdde152020-08-14 20:46:21 -0700307 unique case (state_q)
308
Timothy Chen04834fd2020-09-11 14:58:32 -0700309 StIdle: begin
Timothy Chena49dc7b2020-09-15 17:02:03 -0700310 if (init_q) begin
Timothy Chenf52a4612020-12-04 20:37:49 -0800311 state_d = StReqAddrKey;
312 end
313 end
314
315 StReqAddrKey: begin
Timothy Chen6efde1e2021-04-16 15:39:23 -0700316 phase = PhaseSeed;
Timothy Chenf52a4612020-12-04 20:37:49 -0800317 addr_key_req_d = 1'b1;
318 if (addr_key_ack_q) begin
319 state_d = StReqDataKey;
320 end
321 end
322
323 StReqDataKey: begin
Timothy Chen6efde1e2021-04-16 15:39:23 -0700324 phase = PhaseSeed;
Timothy Chenf52a4612020-12-04 20:37:49 -0800325 data_key_req_d = 1'b1;
326 if (data_key_ack_q) begin
327 // provision_en is only a "good" value after otp/lc initialization
Timothy Chen04834fd2020-09-11 14:58:32 -0700328 state_d = provision_en_i ? StReadSeeds : StWait;
329 end
330 end
331
Timothy Chen5cdde152020-08-14 20:46:21 -0700332 // read seeds
333 StReadSeeds: begin
334 // seeds can be updated in this state
Timothy Chen8204f1d2020-09-02 19:05:39 -0700335 phase = PhaseSeed;
Timothy Chen5cdde152020-08-14 20:46:21 -0700336
337 // kick off flash transaction
338 start = 1'b1;
339 addr = BusAddrW'(seed_page_addr);
Timothy Chen782f27a2020-09-17 22:57:57 -0700340 info_sel = seed_info_sel;
Timothy Chen5cdde152020-08-14 20:46:21 -0700341
342 // we have checked all seeds, proceed
Timothy Chen6efde1e2021-04-16 15:39:23 -0700343 if (seed_cnt_q == NumSeeds) begin
Timothy Chen5cdde152020-08-14 20:46:21 -0700344 start = 1'b0;
345 state_d = StWait;
346
347 // still reading curent seed, increment whenever data returns
348 end else if (!done_i) begin
349 addr_cnt_en = rvalid_i;
350
351 // current seed reading is complete
352 // error is intentionally not used here, as we do not want read seed
353 // failures to stop the software from using flash
Timothy Chenc0b28742020-09-14 12:18:08 -0700354 // When there are upstream failures, the data returned is simply all 1's.
Timothy Chen8204f1d2020-09-02 19:05:39 -0700355 // So instead of doing anything explicit, a status is indicated for software.
Timothy Chen5cdde152020-08-14 20:46:21 -0700356 end else if (done_i) begin
357 addr_cnt_clr = 1'b1;
Timothy Chen8204f1d2020-09-02 19:05:39 -0700358 seed_err_o = 1'b1;
Timothy Chen5cdde152020-08-14 20:46:21 -0700359
360 // we move to the next seed only if current seed is read and validated
361 // if not, flip to validate phase and read seed again
362 if (validate_q) begin
363 seed_cnt_en = 1'b1;
364 validate_d = 1'b0;
365 end else begin
366 validate_d = 1'b1;
367 end
368 end
369 end
370
371 // Waiting for an rma entry command
372 StWait: begin
Timothy Chen6b241b32020-11-13 15:15:45 -0800373 rd_buf_en_o = 1'b1;
Cindy Chen39b14342021-01-29 16:25:24 -0800374 if (rma_req[0] == lc_ctrl_pkg::On) begin
Timothy Chenaeffadc2020-12-11 15:03:07 -0800375 state_d = StEntropyReseed;
376 end
377 end
378
Timothy Chend39402a2020-12-15 20:34:09 -0800379 // Reseed entropy
Timothy Chenaeffadc2020-12-11 15:03:07 -0800380 StEntropyReseed: begin
381 edn_req_o = 1'b1;
382 if(edn_ack_i) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800383 state_d = StRmaWipe;
Timothy Chen5cdde152020-08-14 20:46:21 -0700384 end
385 end
386
Timothy Chend39402a2020-12-15 20:34:09 -0800387 StRmaWipe: begin
Timothy Chen8204f1d2020-09-02 19:05:39 -0700388 phase = PhaseRma;
Timothy Chenaeffadc2020-12-11 15:03:07 -0800389 lfsr_en_o = 1'b1;
Timothy Chend39402a2020-12-15 20:34:09 -0800390 rma_wipe_req = 1'b1;
Timothy Chen5cdde152020-08-14 20:46:21 -0700391
Rupert Swarbrick723c05e2021-03-30 09:26:17 +0100392 if (rma_wipe_idx == MaxWipeEntry[WipeIdxWidth-1:0] && rma_wipe_done) begin
Timothy Chen5e856072020-12-17 14:48:06 -0800393 // first check for error status
394 // If error status is set, go directly to invalid terminal state
395 // If error status is good, go to second check
396 state_d = (err_sts != lc_ctrl_pkg::On) ? StInvalid : StRmaRsp;
Timothy Chend39402a2020-12-15 20:34:09 -0800397 end else if (rma_wipe_done) begin
398 rma_wipe_idx_incr = 1;
Timothy Chen5cdde152020-08-14 20:46:21 -0700399 end
400 end
401
402 // response to rma request
Timothy Chen5e856072020-12-17 14:48:06 -0800403 // Second check for error status:
404 // If error status indicates error, jump to invalid terminal state
405 // Otherwise assign output to error status;
406 // TODO: consider lengthening the check
Timothy Chen5cdde152020-08-14 20:46:21 -0700407 StRmaRsp: begin
Timothy Chen8204f1d2020-09-02 19:05:39 -0700408 phase = PhaseRma;
Timothy Chend39402a2020-12-15 20:34:09 -0800409 if (err_sts != lc_ctrl_pkg::On) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800410 state_d = StInvalid;
Timothy Chen5e856072020-12-17 14:48:06 -0800411 end else begin
412 rma_ack_d = err_sts;
Timothy Chend39402a2020-12-15 20:34:09 -0800413 end
Timothy Chen8204f1d2020-09-02 19:05:39 -0700414 end
415
Timothy Chend39402a2020-12-15 20:34:09 -0800416 // Invalid catch-all state
417 default: begin
Timothy Chen8204f1d2020-09-02 19:05:39 -0700418 phase = PhaseInvalid;
Timothy Chend39402a2020-12-15 20:34:09 -0800419 rma_ack_d = lc_ctrl_pkg::Off;
Timothy Chen8204f1d2020-09-02 19:05:39 -0700420 state_d = StInvalid;
Timothy Chen5cdde152020-08-14 20:46:21 -0700421 end
422
Timothy Chen5cdde152020-08-14 20:46:21 -0700423 endcase // unique case (state_q)
424
425 end // always_comb
426
Timothy Chend39402a2020-12-15 20:34:09 -0800427 ///////////////////////////////
428 // RMA wiping Mechanism
429 ///////////////////////////////
430
Rupert Swarbrick723c05e2021-03-30 09:26:17 +0100431 localparam int unsigned PageCntWidth = prim_util_pkg::vbits(PagesPerBank + 1);
432 localparam int unsigned WordCntWidth = prim_util_pkg::vbits(BusWordsPerPage + 1);
433 localparam int unsigned BeatCntWidth = prim_util_pkg::vbits(WidthMultiple);
434 localparam int unsigned MaxBeatCnt = WidthMultiple - 1;
Timothy Chend39402a2020-12-15 20:34:09 -0800435
436 logic page_cnt_ld;
437 logic page_cnt_incr;
438 logic page_cnt_clr;
439 logic word_cnt_incr;
440 logic word_cnt_clr;
441 logic prog_cnt_en;
442 logic rd_cnt_en;
443 logic beat_cnt_clr;
444 logic [PageCntWidth-1:0] page_cnt, end_page;
445 logic [WordCntWidth-1:0] word_cnt;
446 logic [BeatCntWidth-1:0] beat_cnt;
447 logic [WidthMultiple-1:0][BusWidth-1:0] prog_data;
448
449 assign end_page = RmaWipeEntries[rma_wipe_idx].start_page +
450 RmaWipeEntries[rma_wipe_idx].num_pages;
451
452 typedef enum logic [2:0] {
453 StRmaIdle,
454 StRmaPageSel,
455 StRmaErase,
456 StRmaWordSel,
457 StRmaProgram,
458 StRmaProgramWait,
459 StRmaRdVerify
460 } rma_state_e;
461
462 rma_state_e rma_state_d, rma_state_q;
463
464 always_ff @(posedge clk_i or negedge rst_ni) begin
465 if (!rst_ni) begin
466 rma_state_q <= StRmaIdle;
467 end else begin
468 rma_state_q <= rma_state_d;
469 end
470 end
471
472 always_ff @(posedge clk_i or negedge rst_ni) begin
473 if (!rst_ni) begin
474 page_cnt <= '0;
475 end else if (page_cnt_clr) begin
476 page_cnt <= '0;
477 end else if (page_cnt_ld) begin
478 page_cnt <= RmaWipeEntries[rma_wipe_idx].start_page;
479 end else if (page_cnt_incr) begin
480 page_cnt <= page_cnt + 1'b1;
481 end
482 end
483
484 always_ff @(posedge clk_i or negedge rst_ni) begin
485 if (!rst_ni) begin
486 word_cnt <= '0;
487 end else if (word_cnt_clr) begin
488 word_cnt <= '0;
489 end else if (word_cnt_incr) begin
Timothy Chen6efde1e2021-04-16 15:39:23 -0700490 word_cnt <= word_cnt + WidthMultiple;
Timothy Chend39402a2020-12-15 20:34:09 -0800491 end
492 end
493
494 always_ff @(posedge clk_i or negedge rst_ni) begin
495 if (!rst_ni) begin
496 rma_wipe_idx <= '0;
497 end else if (rma_wipe_idx_incr) begin
498 rma_wipe_idx <= rma_wipe_idx + 1'b1;
499 end
500 end
501
502 always_ff @(posedge clk_i or negedge rst_ni) begin
503 if (!rst_ni) begin
504 beat_cnt <= '0;
505 end else if (beat_cnt_clr) begin
506 beat_cnt <= '0;
507 end else if (prog_cnt_en) begin
508 if (wvalid_o && wready_i) begin
509 beat_cnt <= beat_cnt + 1'b1;
510 end
511 end else if (rd_cnt_en) begin
512 if (rvalid_i && rready_o) begin
513 beat_cnt <= beat_cnt + 1'b1;
514 end
515 end
516 end
517
518 // latch data programmed
519 always_ff @(posedge clk_i) begin
520 if (prog_cnt_en && wvalid_o && wready_i) begin
521 prog_data[beat_cnt] <= rand_i;
522 end
523 end
524
525 // once error is set to off, it cannot be unset without a reboot
Timothy Chen5e856072020-12-17 14:48:06 -0800526 // On - no errors
527 // Off - errors were observed
Timothy Chend39402a2020-12-15 20:34:09 -0800528 always_ff @(posedge clk_i or negedge rst_ni) begin
529 if (!rst_ni) begin
530 err_sts <= lc_ctrl_pkg::On;
Timothy Chen5e856072020-12-17 14:48:06 -0800531 end else if (err_sts_set && (err_sts != lc_ctrl_pkg::Off)) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800532 err_sts <= lc_ctrl_pkg::Off;
533 end
534 end
535
536 logic rma_start;
537 logic [BusAddrW-1:0] rma_addr;
538 flash_op_e rma_op;
539 flash_part_e rma_part_sel;
540 logic [InfoTypesWidth-1:0] rma_info_sel;
541 logic [11:0] rma_num_words;
542
543 assign rma_addr = {RmaWipeEntries[rma_wipe_idx].bank,
544 page_cnt[PageW-1:0],
545 word_cnt[BusWordW-1:0]};
546
547 assign rma_part_sel = RmaWipeEntries[rma_wipe_idx].part;
548 assign rma_info_sel = RmaWipeEntries[rma_wipe_idx].info_sel;
Timothy Chen6efde1e2021-04-16 15:39:23 -0700549 assign rma_num_words = WidthMultiple - 1;
Timothy Chend39402a2020-12-15 20:34:09 -0800550
551
552 //fsm for handling the actual wipe
553 always_comb begin
554 rma_state_d = rma_state_q;
555 rma_wipe_done = 1'b0;
556 rma_start = 1'b0;
557 rma_op = FlashOpInvalid;
558 err_sts_set = 1'b0;
559 page_cnt_ld = 1'b0;
560 page_cnt_incr = 1'b0;
561 page_cnt_clr = 1'b0;
562 word_cnt_incr = 1'b0;
563 word_cnt_clr = 1'b0;
564 prog_cnt_en = 1'b0;
565 rd_cnt_en = 1'b0;
566 beat_cnt_clr = 1'b0;
567
568 unique case (rma_state_q)
569
570 StRmaIdle: begin
571 if (rma_wipe_req) begin
572 rma_state_d = StRmaPageSel;
573 page_cnt_ld = 1'b1;
574 end
575 end
576
577 StRmaPageSel: begin
578 if (page_cnt < end_page) begin
579 rma_state_d = StRmaErase;
580 end else begin
581 rma_wipe_done = 1'b1;
582 page_cnt_clr = 1'b1;
583 rma_state_d = StRmaIdle;
584 end
585 end
586
587 StRmaErase: begin
588 rma_start = 1'b1;
589 rma_op = FlashOpErase;
590 if (done_i) begin
591 err_sts_set = err_i;
592 rma_state_d = StRmaWordSel;
593 end
594 end
595
596 StRmaWordSel: begin
Timothy Chen6efde1e2021-04-16 15:39:23 -0700597 if (word_cnt < BusWordsPerPage) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800598 rma_state_d = StRmaProgram;
599 end else begin
600 word_cnt_clr = 1'b1;
601 page_cnt_incr = 1'b1;
602 rma_state_d = StRmaPageSel;
603 end
604 end
605
606 StRmaProgram: begin
607 rma_start = 1'b1;
608 rma_op = FlashOpProgram;
609 prog_cnt_en = 1'b1;
610
Rupert Swarbrick723c05e2021-03-30 09:26:17 +0100611 if ((beat_cnt == MaxBeatCnt[BeatCntWidth-1:0]) && wready_i) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800612 rma_state_d = StRmaProgramWait;
613 end
614 end
615
616 StRmaProgramWait: begin
617 rma_start = 1'b1;
618 rma_op = FlashOpProgram;
619
620 if (done_i) begin
621 beat_cnt_clr = 1'b1;
622 err_sts_set = err_i;
623 rma_state_d = StRmaRdVerify;
624 end
625 end
626
627 StRmaRdVerify: begin
628 rma_start = 1'b1;
629 rma_op = FlashOpRead;
630 rd_cnt_en = 1'b1;
631
Rupert Swarbrick723c05e2021-03-30 09:26:17 +0100632 if ((beat_cnt == MaxBeatCnt[BeatCntWidth-1:0]) && done_i) begin
Timothy Chend39402a2020-12-15 20:34:09 -0800633 beat_cnt_clr = 1'b1;
634 word_cnt_incr = 1'b1;
635 rma_state_d = StRmaWordSel;
636 end
637
638 if (rvalid_i && rready_o) begin
639 err_sts_set = prog_data[beat_cnt] != rdata_i;
640 end
641 end
642
643 default: begin
644 err_sts_set = 1'b1;
645 end
646
647 endcase // unique case (rma_state_q)
648 end // always_comb
649
650 assign wdata_o = rand_i;
651 assign wvalid_o = prog_cnt_en;
652 assign ctrl_o.start.q = seed_phase ? start : rma_start;
653 assign ctrl_o.op.q = seed_phase ? op : rma_op;
Timothy Chen103b4cb2020-09-12 15:31:37 -0700654 assign ctrl_o.prog_sel.q = prog_type;
Timothy Chen5cdde152020-08-14 20:46:21 -0700655 assign ctrl_o.erase_sel.q = erase_type;
Timothy Chend39402a2020-12-15 20:34:09 -0800656 assign ctrl_o.partition_sel.q = seed_phase ? part_sel : rma_part_sel;
657 assign ctrl_o.info_sel.q = seed_phase ? info_sel : rma_info_sel;
658 assign ctrl_o.num = seed_phase ? num_words : rma_num_words;
Timothy Chen2df95612020-08-31 15:29:12 -0700659 // address is consistent with software width format (full bus)
Timothy Chend39402a2020-12-15 20:34:09 -0800660 assign addr_o = seed_phase ? top_pkg::TL_AW'({addr, {BusByteWidth{1'b0}}}) :
661 top_pkg::TL_AW'({rma_addr, {BusByteWidth{1'b0}}});
Timothy Chen5cdde152020-08-14 20:46:21 -0700662 assign init_busy_o = seed_phase;
663 assign req_o = seed_phase | rma_phase;
664 assign rready_o = 1'b1;
665 assign seeds_o = seeds_q;
Timothy Chen8204f1d2020-09-02 19:05:39 -0700666 assign phase_o = phase;
Timothy Chen5cdde152020-08-14 20:46:21 -0700667
Timothy Chend39402a2020-12-15 20:34:09 -0800668 assign rma_ack_o = rma_ack_q;
669
Timothy Chenf52a4612020-12-04 20:37:49 -0800670 logic unused_seed_valid;
671 assign unused_seed_valid = otp_key_rsp_i.seed_valid;
672
Timothy Chen5cdde152020-08-14 20:46:21 -0700673endmodule // flash_ctrl_lcmgr