1use core::cell::Cell;
8use core::ops::{Index, IndexMut};
9use kernel::hil;
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::cells::TakeCell;
12use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
13use kernel::utilities::registers::{
14 register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
15};
16use kernel::utilities::StaticRef;
17use kernel::ErrorCode;
18
19register_structs! {
20 pub FlashCtrlRegisters {
21 (0x000 => intr_state: ReadWrite<u32, INTR::Register>),
22 (0x004 => intr_enable: ReadWrite<u32, INTR::Register>),
23 (0x008 => intr_test: WriteOnly<u32, INTR::Register>),
24 (0x00C => alert_test: WriteOnly<u32>),
25 (0x010 => disable: ReadWrite<u32>),
26 (0x014 => exec: ReadWrite<u32>),
27 (0x018 => init: ReadWrite<u32, INIT::Register>),
28 (0x01C => ctrl_regwen: ReadOnly<u32, CTRL_REGWEN::Register>),
29 (0x020 => control: ReadWrite<u32, CONTROL::Register>),
30 (0x024 => addr: ReadWrite<u32, ADDR::Register>),
31 (0x028 => prog_type_en: ReadWrite<u32, PROG_TYPE_EN::Register>),
32 (0x02c => erase_suspend: ReadWrite<u32, ERASE_SUSPEND::Register>),
33 (0x030 => region_cfg_regwen: [ReadWrite<u32, REGION_CFG_REGWEN::Register>; 8]),
34 (0x050 => mp_region_cfg: [ReadWrite<u32, MP_REGION_CFG::Register>; 8]),
35 (0x070 => mp_region: [ReadWrite<u32, MP_REGION::Register>; 8]),
36 (0x090 => default_region: ReadWrite<u32, DEFAULT_REGION::Register>),
37
38 (0x094 => bank0_info0_regwen: [ReadWrite<u32, BANK_INFO_REGWEN::Register>; 10]),
39 (0x0BC => bank0_info0_page_cfg: [ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>; 10]),
40 (0x0E4 => bank0_info1_regwen: ReadWrite<u32, BANK_INFO_REGWEN::Register>),
41 (0x0E8 => bank0_info1_page_cfg: ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>),
42 (0x0EC => bank0_info2_regwen: [ReadWrite<u32, BANK_INFO_REGWEN::Register>; 2]),
43 (0x0F4 => bank0_info2_page_cfg: [ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>; 2]),
44
45 (0x0FC => bank1_info0_regwen: [ReadWrite<u32, BANK_INFO_REGWEN::Register>; 10]),
46 (0x124 => bank1_info0_page_cfg: [ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>; 10]),
47 (0x14C => bank1_info1_regwen: ReadWrite<u32, BANK_INFO_REGWEN::Register>),
48 (0x150 => bank1_info1_page_cfg: ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>),
49 (0x154 => bank1_info2_regwen: [ReadWrite<u32, BANK_INFO_REGWEN::Register>; 2]),
50 (0x15C => bank1_info2_page_cfg: [ReadWrite<u32, BANK_INFO_PAGE_CFG::Register>; 2]),
51
52 (0x164 => hw_info_cfg_override: ReadWrite<u32>),
53 (0x168 => bank_cfg_regwen: ReadWrite<u32, BANK_CFG_REGWEN::Register>),
54 (0x16C => mp_bank_cfg_shadowed: ReadWrite<u32, MP_BANK_CFG::Register>),
55 (0x170 => op_status: ReadWrite<u32, OP_STATUS::Register>),
56 (0x174 => status: ReadOnly<u32, STATUS::Register>),
57 (0x178 => debug_state: ReadOnly<u32>),
58 (0x17C => err_code: ReadWrite<u32, ERR_CODE::Register>),
59 (0x180 => std_fault_status: ReadOnly<u32>),
60 (0x184 => fault_status: ReadOnly<u32>),
61 (0x188 => err_addr: ReadOnly<u32>),
62 (0x18C => ecc_single_err_cnt: ReadOnly<u32>),
63 (0x190 => ecc_single_addr: [ReadOnly<u32>; 2]),
64 (0x198 => phy_alert_cfg: ReadOnly<u32>),
65 (0x19C => phy_status: ReadOnly<u32, PHY_STATUS::Register>),
66 (0x1A0 => scratch: ReadWrite<u32, SCRATCH::Register>),
67 (0x1A4 => fifo_lvl: ReadWrite<u32, FIFO_LVL::Register>),
68 (0x1A8 => fifo_rst: ReadWrite<u32, FIFO_RST::Register>),
69 (0x1AC => curr_fifo_lvl: WriteOnly<u32>),
70 (0x1B0 => prog_fifo: WriteOnly<u32>),
71 (0x1B4 => rd_fifo: ReadOnly<u32>),
72 (0x1B8=> @END),
73 }
74}
75
76register_bitfields![u32,
77 INTR [
78 PROG_EMPTY OFFSET(0) NUMBITS(1) [],
79 PROG_LVL OFFSET(1) NUMBITS(1) [],
80 RD_FULL OFFSET(2) NUMBITS(1) [],
81 RD_LVL OFFSET(3) NUMBITS(1) [],
82 OP_DONE OFFSET(4) NUMBITS(1) [],
83 OP_ERROR OFFSET(5) NUMBITS(1) []
84 ],
85 INIT [
86 VAL OFFSET(0) NUMBITS(1) []
87 ],
88 CTRL_REGWEN [
89 EN OFFSET(0) NUMBITS(1) []
90 ],
91 CONTROL [
92 START OFFSET(0) NUMBITS(1) [],
93 OP OFFSET(4) NUMBITS(2) [
94 READ = 0,
95 PROG = 1,
96 ERASE = 2
97 ],
98 PROG_SEL OFFSET(6) NUMBITS(1) [
99 NORMAL = 0,
100 REPAIR = 1,
101 ],
102 ERASE_SEL OFFSET(7) NUMBITS(1) [
103 PAGE = 0,
104 BANK = 1
105 ],
106 PARTITION_SEL OFFSET(8) NUMBITS(1) [
107 DATA = 0,
110 INFO = 1
113 ],
114 INFO_SEL OFFSET(9) NUMBITS(2) [],
115 NUM OFFSET(16) NUMBITS(12) []
116 ],
117 ERR_CODE [
118 OP_ERR OFFSET(0) NUMBITS(1) [],
119 MP_ERR OFFSET(1) NUMBITS(1) [],
120 RD_ERR OFFSET(2) NUMBITS(1) [],
121 PROG_ERR OFFSET(3) NUMBITS(1) [],
122 PROG_WIN_ERR OFFSET(4) NUMBITS(1) [],
123 PROG_TYPE_ERR OFFSET(5) NUMBITS(1) [],
124 UPDATE_ERR OFFSET(6) NUMBITS(1) [],
125 ],
126 PROG_TYPE_EN [
127 NORMAL OFFSET(0) NUMBITS(1) [],
128 REPAIR OFFSET(1) NUMBITS(1) [],
129 ],
130 ERASE_SUSPEND [
131 REQ OFFSET(0) NUMBITS(1) [],
132 ],
133 ADDR [
134 START OFFSET(0) NUMBITS(32) []
135 ],
136 REGION_CFG_REGWEN [
137 REGION OFFSET(0) NUMBITS(1) [
138 Locked = 0,
140 Enabled = 1,
142 ]
143 ],
144 MP_REGION_CFG [
145 EN OFFSET(0) NUMBITS(4) [
148 Set = 0x6,
149 Clear = 0x9,
150 ],
151 RD_EN OFFSET(4) NUMBITS(4) [
152 Set = 0x6,
153 Clear = 0x9,
154 ],
155 PROG_EN OFFSET(8) NUMBITS(4) [
156 Set = 0x6,
157 Clear = 0x9,
158 ],
159 ERASE_EN OFFSET(12) NUMBITS(4) [
160 Set = 0x6,
161 Clear = 0x9,
162 ],
163 SCRAMBLE_EN OFFSET(16) NUMBITS(4) [
164 Set = 0x6,
165 Clear = 0x9,
166 ],
167 ECC_EN OFFSET(20) NUMBITS(4) [
168 Set = 0x6,
169 Clear = 0x9,
170 ],
171 HE_EN OFFSET(24) NUMBITS(4) [
172 Set = 0x6,
173 Clear = 0x9,
174 ],
175 ],
176 MP_REGION [
177 BASE OFFSET(0) NUMBITS(9) [],
178 SIZE OFFSET(10) NUMBITS(10) []
179 ],
180 BANK_INFO_REGWEN [
181 REGION OFFSET(0) NUMBITS(1) [
182 Locked = 0,
183 Enabled =1,
184 ]
185 ],
186 BANK_INFO_PAGE_CFG [
187 EN OFFSET(0) NUMBITS(4) [
188 Set = 0x6,
189 Clear = 0x9,
190 ],
191 RD_EN OFFSET(4) NUMBITS(4) [
192 Set = 0x6,
193 Clear = 0x9,
194 ],
195 PROG_EN OFFSET(8) NUMBITS(4) [
196 Set = 0x6,
197 Clear = 0x9,
198 ],
199 ERASE_EN OFFSET(12) NUMBITS(4) [
200 Set = 0x6,
201 Clear = 0x9,
202 ],
203 SCRAMBLE_EN OFFSET(16) NUMBITS(4) [
204 Set = 0x6,
205 Clear = 0x9,
206 ],
207 ECC_EN OFFSET(20) NUMBITS(4) [
208 Set = 0x6,
209 Clear = 0x9,
210 ],
211 HE_EN OFFSET(24) NUMBITS(4) [
212 Set = 0x6,
213 Clear = 0x9,
214 ],
215 ],
216 BANK_CFG_REGWEN [
217 BANK OFFSET(0) NUMBITS(1) []
218 ],
219 DEFAULT_REGION [
220 RD_EN OFFSET(0) NUMBITS(4) [
221 Set = 0x6,
222 Clear = 0x9,
223 ],
224 PROG_EN OFFSET(4) NUMBITS(4) [
225 Set = 0x6,
226 Clear = 0x9,
227 ],
228 ERASE_EN OFFSET(8) NUMBITS(4) [
229 Set = 0x6,
230 Clear = 0x9,
231 ],
232 SCRAMBLE_EN OFFSET(12) NUMBITS(4) [
233 Set = 0x6,
234 Clear = 0x9,
235 ],
236 ECC_EN OFFSET(16) NUMBITS(4) [
237 Set = 0x6,
238 Clear = 0x9,
239 ],
240 HE_EN OFFSET(20) NUMBITS(4) [
241 Set = 0x6,
242 Clear = 0x9,
243 ],
244 ],
245 MP_BANK_CFG [
246 ERASE_EN_0 OFFSET(0) NUMBITS(1) [],
247 ERASE_EN_1 OFFSET(1) NUMBITS(1) []
248 ],
249 OP_STATUS [
250 DONE OFFSET(0) NUMBITS(1) [],
251 ERR OFFSET(1) NUMBITS(1) []
252 ],
253 STATUS [
254 RD_FULL OFFSET(0) NUMBITS(1) [],
255 RD_EMPTY OFFSET(1) NUMBITS(1) [],
256 PROG_FULL OFFSET(2) NUMBITS(1) [],
257 PROG_EMPTY OFFSET(3) NUMBITS(1) [],
258 INIT_WIP OFFSET(4) NUMBITS(1) [],
259 ],
260 PHY_STATUS [
261 INIT_WIP OFFSET(0) NUMBITS(1) [],
262 PROG_NORMAL_AVAIL OFFSET(1) NUMBITS(1) [],
263 PROG_REPAIR_AVAIL OFFSET(2) NUMBITS(1) []
264 ],
265 SCRATCH [
266 DATA OFFSET(0) NUMBITS(32) []
267 ],
268 FIFO_LVL [
269 PROG OFFSET(0) NUMBITS(5) [],
270 RD OFFSET(8) NUMBITS(5) []
271 ],
272 FIFO_RST [
273 EN OFFSET(0) NUMBITS(1) []
274 ]
275];
276
277pub const PAGE_SIZE: usize = 2048;
278pub const FLASH_ADDR_OFFSET: usize = 0x20000000;
279pub const FLASH_WORD_SIZE: usize = 8;
280pub const FLASH_PAGES_PER_BANK: usize = 256;
281pub const FLASH_NUM_BANKS: usize = 2;
282pub const FLASH_MAX_PAGES: usize = FLASH_NUM_BANKS * FLASH_PAGES_PER_BANK;
283pub const FLASH_NUM_BUSWORDS_PER_BANK: usize = PAGE_SIZE / 4;
284pub const FLASH_MP_MAX_CFGS: usize = 8;
285pub const FLASH_PROG_WINDOW_SIZE: usize = 16;
287pub const FLASH_PROG_WINDOW_MASK: u32 = 0xFFFFFFF0;
288
289pub struct LowRiscPage(pub [u8; PAGE_SIZE]);
290
291#[derive(PartialEq, Debug)]
297pub struct FlashMPConfig {
298 pub read_en: bool,
300 pub write_en: bool,
302 pub erase_en: bool,
304 pub scramble_en: bool,
306 pub ecc_en: bool,
308 pub he_en: bool,
310}
311
312impl Default for LowRiscPage {
313 fn default() -> Self {
314 Self([0; PAGE_SIZE])
315 }
316}
317
318impl Index<usize> for LowRiscPage {
319 type Output = u8;
320
321 fn index(&self, idx: usize) -> &u8 {
322 &self.0[idx]
323 }
324}
325
326impl IndexMut<usize> for LowRiscPage {
327 fn index_mut(&mut self, idx: usize) -> &mut u8 {
328 &mut self.0[idx]
329 }
330}
331
332impl AsMut<[u8]> for LowRiscPage {
333 fn as_mut(&mut self) -> &mut [u8] {
334 &mut self.0
335 }
336}
337
338#[derive(PartialEq)]
339enum FlashBank {
340 BANK0 = 0,
341 BANK1 = 1,
342}
343
344#[derive(PartialEq, Clone, Copy)]
345pub enum FlashRegion {
346 REGION0 = 0,
347 REGION1 = 1,
348 REGION2 = 2,
349 REGION3 = 3,
350 REGION4 = 4,
351 REGION5 = 5,
352 REGION6 = 6,
353 REGION7 = 7,
354}
355
356pub struct FlashCtrl<'a> {
357 registers: StaticRef<FlashCtrlRegisters>,
358 flash_client: OptionalCell<&'a dyn hil::flash::Client<FlashCtrl<'a>>>,
359 data_configured: Cell<bool>,
360 info_configured: Cell<bool>,
361 read_buf: TakeCell<'static, LowRiscPage>,
362 read_index: Cell<usize>,
363 write_buf: TakeCell<'static, LowRiscPage>,
364 write_index: Cell<usize>,
365 write_word_addr: Cell<usize>,
366 region_num: FlashRegion,
367}
368
369impl FlashCtrl<'_> {
370 pub fn new(base: StaticRef<FlashCtrlRegisters>, region_num: FlashRegion) -> Self {
371 FlashCtrl {
372 registers: base,
373 flash_client: OptionalCell::empty(),
374 data_configured: Cell::new(false),
375 info_configured: Cell::new(false),
376 read_buf: TakeCell::empty(),
377 read_index: Cell::new(0),
378 write_buf: TakeCell::empty(),
379 write_index: Cell::new(0),
380 write_word_addr: Cell::new(0),
381 region_num,
382 }
383 }
384
385 fn enable_interrupts(&self) {
386 self.registers.intr_enable.write(
388 INTR::PROG_EMPTY::SET
389 + INTR::PROG_LVL::CLEAR
390 + INTR::RD_FULL::CLEAR
391 + INTR::RD_LVL::SET
392 + INTR::OP_DONE::SET
393 + INTR::OP_ERROR::SET,
394 );
395 }
396
397 fn disable_interrupts(&self) {
398 self.registers.intr_enable.set(0x00);
400 self.registers.intr_state.set(0xFFFF_FFFF);
401 }
402
403 fn calculate_max_prog_len(&self, word_addr: u32, rem_bytes: u32) -> u32 {
408 let window_limit =
410 ((word_addr + FLASH_PROG_WINDOW_SIZE as u32) & FLASH_PROG_WINDOW_MASK) - word_addr;
411 let words_to_write = rem_bytes / 4;
412
413 if words_to_write < window_limit {
414 words_to_write
415 } else {
416 window_limit
417 }
418 }
419
420 fn configure_data_partition(&self, num: FlashRegion) -> Result<(), ErrorCode> {
421 self.registers.default_region.write(
422 DEFAULT_REGION::RD_EN::Set
423 + DEFAULT_REGION::PROG_EN::Set
424 + DEFAULT_REGION::ERASE_EN::Set,
425 );
426
427 if let Some(mp_region_cfg) = self.registers.mp_region_cfg.get(num as usize) {
428 mp_region_cfg.write(
429 MP_REGION_CFG::RD_EN::Set
430 + MP_REGION_CFG::PROG_EN::Set
431 + MP_REGION_CFG::ERASE_EN::Set
432 + MP_REGION_CFG::SCRAMBLE_EN::Clear
433 + MP_REGION_CFG::ECC_EN::Clear
434 + MP_REGION_CFG::EN::Clear,
435 );
436
437 if let Some(mp_region) = self.registers.mp_region.get(num as usize) {
438 mp_region.write(
440 MP_REGION::BASE.val(FLASH_PAGES_PER_BANK as u32) + MP_REGION::SIZE.val(0x1),
441 );
442 } else {
443 return Err(ErrorCode::INVAL);
444 }
445
446 mp_region_cfg.modify(MP_REGION_CFG::EN::Set);
448 } else {
449 return Err(ErrorCode::INVAL);
450 }
451
452 self.data_configured.set(true);
453 Ok(())
454 }
455
456 fn configure_info_partition(&self, bank: FlashBank, num: FlashRegion) -> Result<(), ErrorCode> {
457 if bank == FlashBank::BANK0 {
458 if let Some(bank0_info0_page_cfg) =
459 self.registers.bank0_info0_page_cfg.get(num as usize)
460 {
461 bank0_info0_page_cfg.write(
462 BANK_INFO_PAGE_CFG::RD_EN::Set
463 + BANK_INFO_PAGE_CFG::PROG_EN::Set
464 + BANK_INFO_PAGE_CFG::ERASE_EN::Set
465 + BANK_INFO_PAGE_CFG::SCRAMBLE_EN::Set
466 + BANK_INFO_PAGE_CFG::ECC_EN::Set
467 + BANK_INFO_PAGE_CFG::EN::Clear,
468 );
469 bank0_info0_page_cfg.modify(BANK_INFO_PAGE_CFG::EN::Set);
470 } else {
471 return Err(ErrorCode::INVAL);
472 }
473 } else if bank == FlashBank::BANK1 {
474 if let Some(bank1_info0_page_cfg) =
475 self.registers.bank1_info0_page_cfg.get(num as usize)
476 {
477 bank1_info0_page_cfg.write(
478 BANK_INFO_PAGE_CFG::RD_EN::Set
479 + BANK_INFO_PAGE_CFG::PROG_EN::Set
480 + BANK_INFO_PAGE_CFG::ERASE_EN::Set
481 + BANK_INFO_PAGE_CFG::SCRAMBLE_EN::Set
482 + BANK_INFO_PAGE_CFG::ECC_EN::Set
483 + BANK_INFO_PAGE_CFG::EN::Clear,
484 );
485 bank1_info0_page_cfg.modify(BANK_INFO_PAGE_CFG::EN::Set);
486 } else {
487 return Err(ErrorCode::INVAL);
488 }
489 } else {
490 return Err(ErrorCode::INVAL);
491 }
492 self.info_configured.set(true);
493 Ok(())
494 }
495
496 pub fn reset_fifos(&self) {
499 self.registers.fifo_rst.write(FIFO_RST::EN::SET);
502 self.registers.fifo_rst.write(FIFO_RST::EN::CLEAR);
503 }
504
505 pub fn handle_interrupt(&self) {
506 let irqs = self.registers.intr_state.extract();
507 let mp_fault = self.registers.err_code.is_set(ERR_CODE::MP_ERR);
510
511 self.disable_interrupts();
512
513 if irqs.is_set(INTR::OP_ERROR) || mp_fault {
514 self.registers.op_status.set(0);
515 self.registers.err_code.set(0xFFFF_FFFF);
517 self.reset_fifos();
518
519 let read_buf = self.read_buf.take();
520 let error = if mp_fault {
521 hil::flash::Error::FlashMemoryProtectionError
522 } else {
523 hil::flash::Error::FlashError
524 };
525 if let Some(buf) = read_buf {
526 self.flash_client.map(move |client| {
528 client.read_complete(buf, Err(error));
529 });
530 }
531
532 let write_buf = self.write_buf.take();
533 if let Some(buf) = write_buf {
534 self.flash_client.map(move |client| {
536 client.write_complete(buf, Err(error));
537 });
538 }
539
540 if self.registers.control.matches_all(CONTROL::OP::ERASE) {
541 self.flash_client.map(move |client| {
543 client.erase_complete(Err(error));
544 });
545 }
546 }
547
548 if irqs.is_set(INTR::RD_LVL) {
549 self.read_buf.map(|buf| {
550 while !self.registers.status.is_set(STATUS::RD_EMPTY)
551 && self.read_index.get() < PAGE_SIZE
552 {
553 let data = self.registers.rd_fifo.get().to_ne_bytes();
554 let buf_offset = self.read_index.get();
555
556 buf[buf_offset] = data[0];
557 buf[buf_offset + 1] = data[1];
558 buf[buf_offset + 2] = data[2];
559 buf[buf_offset + 3] = data[3];
560
561 self.read_index.set(buf_offset + 4);
562 }
563 self.enable_interrupts();
564 });
565 }
566
567 if irqs.is_set(INTR::PROG_EMPTY) {
568 self.write_buf.map(|buf| {
569 let transaction_word_len = self.calculate_max_prog_len(
570 self.write_word_addr.get() as u32,
571 (buf.0.len() - self.write_index.get()) as u32,
572 );
573
574 let mut words_written = 0;
575
576 self.registers.control.write(
578 CONTROL::OP::PROG
579 + CONTROL::PARTITION_SEL::DATA
580 + CONTROL::INFO_SEL::CLEAR
581 + CONTROL::NUM.val(transaction_word_len - 1)
582 + CONTROL::START::CLEAR,
583 );
584
585 self.registers
587 .addr
588 .write(ADDR::START.val(self.write_word_addr.get().saturating_mul(4) as u32));
589
590 self.registers.control.modify(CONTROL::START::SET);
592
593 for i in 0..transaction_word_len {
594 if self.registers.status.is_set(STATUS::PROG_FULL) {
595 words_written = i;
596 break;
597 }
598 let buf_offset = self.write_index.get();
599 let data: u32 = buf[buf_offset] as u32
600 | (buf[buf_offset + 1] as u32) << 8
601 | (buf[buf_offset + 2] as u32) << 16
602 | (buf[buf_offset + 3] as u32) << 24;
603
604 self.registers.prog_fifo.set(data);
605
606 self.write_index.set(buf_offset + 4);
607 words_written = i + 1;
609 }
610
611 self.write_word_addr
612 .set(self.write_word_addr.get() + words_written as usize);
613 self.enable_interrupts();
614 });
615 }
616
617 if irqs.is_set(INTR::OP_DONE) {
618 if self.registers.control.matches_all(CONTROL::OP::READ) {
619 let read_buf = self.read_buf.take();
620 if let Some(buf) = read_buf {
621 if self.read_index.get() >= buf.0.len() {
623 self.registers.op_status.set(0);
624 self.flash_client.map(move |client| {
626 client.read_complete(buf, Ok(()));
627 });
628 } else {
629 self.read_buf.replace(buf);
631 self.enable_interrupts();
632 }
633 }
634 } else if self.registers.control.matches_all(CONTROL::OP::PROG) {
635 let write_buf = self.write_buf.take();
636 if let Some(buf) = write_buf {
637 if self.write_index.get() >= buf.0.len() {
639 self.registers.op_status.set(0);
640 self.flash_client.map(move |client| {
642 client.write_complete(buf, Ok(()));
643 });
644 } else {
645 self.write_buf.replace(buf);
647 self.enable_interrupts();
648 }
649 }
650 } else if self.registers.control.matches_all(CONTROL::OP::ERASE) {
651 self.flash_client.map(move |client| {
652 client.erase_complete(Ok(()));
653 });
654 }
655 }
656 }
657
658 fn mp_addr_to_page_range(
674 &self,
675 mut start_addr: usize,
676 mut end_addr: usize,
677 ) -> Result<(usize, usize), ErrorCode> {
678 if start_addr >= end_addr {
679 return Err(ErrorCode::NOSUPPORT);
680 }
681
682 if let Some(addr) = start_addr.checked_sub(FLASH_ADDR_OFFSET) {
685 start_addr = addr;
686 } else {
687 return Err(ErrorCode::NOSUPPORT);
688 }
689 if let Some(addr) = end_addr.checked_sub(FLASH_ADDR_OFFSET) {
690 end_addr = addr;
691 } else {
692 return Err(ErrorCode::NOSUPPORT);
693 }
694
695 let start_page_num = start_addr.saturating_div(PAGE_SIZE);
696 let end_page_num = end_addr.saturating_div(PAGE_SIZE);
697
698 if start_page_num >= FLASH_MAX_PAGES || end_page_num >= FLASH_MAX_PAGES {
699 return Err(ErrorCode::NOSUPPORT);
701 }
702
703 let n_pages_used: usize = end_page_num.saturating_sub(start_page_num).max(1);
706
707 Ok((start_page_num, n_pages_used))
712 }
713
714 pub fn mp_set_region_perms(
750 &self,
751 start_addr: usize,
752 end_addr: usize,
753 region_num: usize,
754 mp_perms: &FlashMPConfig,
755 ) -> Result<(), ErrorCode> {
756 let (page_number, num_pages) = self.mp_addr_to_page_range(start_addr, end_addr)?;
757
758 if region_num > FlashRegion::REGION7 as usize || page_number >= FLASH_MAX_PAGES {
759 return Err(ErrorCode::NOSUPPORT);
760 }
761
762 if num_pages > FLASH_MAX_PAGES - page_number {
764 return Err(ErrorCode::NOSUPPORT);
765 }
766
767 let regs = self.registers;
768
769 if !regs.region_cfg_regwen[region_num].is_set(REGION_CFG_REGWEN::REGION) {
770 return Err(ErrorCode::NOSUPPORT);
772 }
773
774 self.registers.mp_region_cfg[region_num].write(
776 MP_REGION_CFG::EN::Clear
777 + MP_REGION_CFG::RD_EN::Clear
778 + MP_REGION_CFG::PROG_EN::Clear
779 + MP_REGION_CFG::ERASE_EN::Clear
780 + MP_REGION_CFG::SCRAMBLE_EN::Clear
781 + MP_REGION_CFG::ECC_EN::Clear
782 + MP_REGION_CFG::HE_EN::Clear,
783 );
784
785 if mp_perms.read_en {
787 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::RD_EN::Set);
788 }
789
790 if mp_perms.write_en {
791 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::PROG_EN::Set);
792 }
793
794 if mp_perms.erase_en {
795 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::ERASE_EN::Set);
796 }
797
798 if mp_perms.scramble_en {
799 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::SCRAMBLE_EN::Set);
800 }
801
802 if mp_perms.ecc_en {
803 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::ECC_EN::Set);
804 }
805
806 if mp_perms.he_en {
807 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::HE_EN::Set);
808 }
809
810 regs.mp_region[region_num]
814 .write(MP_REGION::BASE.val(page_number as u32) + MP_REGION::SIZE.val(num_pages as u32));
815
816 self.registers.mp_region_cfg[region_num].modify(MP_REGION_CFG::EN::Set);
818
819 Ok(())
820 }
821
822 pub fn mp_read_region_perms(&self, region_num: usize) -> Result<FlashMPConfig, ErrorCode> {
834 if region_num > FlashRegion::REGION7 as usize {
835 return Err(ErrorCode::NOSUPPORT);
836 }
837
838 let mp_cfg = self.registers.mp_region_cfg[region_num].extract();
839
840 let mut cfg = FlashMPConfig {
841 read_en: false,
842 write_en: false,
843 erase_en: false,
844 scramble_en: false,
845 ecc_en: false,
846 he_en: false,
847 };
848
849 if mp_cfg.matches_all(MP_REGION_CFG::RD_EN::Set) {
850 cfg.read_en = true;
851 }
852
853 if mp_cfg.matches_all(MP_REGION_CFG::PROG_EN::Set) {
854 cfg.write_en = true;
855 }
856
857 if mp_cfg.matches_all(MP_REGION_CFG::ERASE_EN::Set) {
858 cfg.erase_en = true;
859 }
860
861 if mp_cfg.matches_all(MP_REGION_CFG::SCRAMBLE_EN::Set) {
862 cfg.scramble_en = true;
863 }
864
865 if mp_cfg.matches_all(MP_REGION_CFG::ECC_EN::Set) {
866 cfg.ecc_en = true;
867 }
868
869 if mp_cfg.matches_all(MP_REGION_CFG::HE_EN::Set) {
870 cfg.he_en = true;
871 }
872
873 Ok(cfg)
874 }
875
876 pub fn mp_get_num_regions(&self) -> Result<u32, ErrorCode> {
884 Ok(FLASH_MP_MAX_CFGS as u32)
885 }
886
887 pub fn mp_is_region_locked(&self, region_num: usize) -> Result<bool, ErrorCode> {
899 if region_num > FlashRegion::REGION7 as usize {
900 return Err(ErrorCode::NOSUPPORT);
901 }
902
903 if !self.registers.region_cfg_regwen[region_num].is_set(REGION_CFG_REGWEN::REGION) {
904 return Ok(true);
906 }
907 Ok(false)
909 }
910
911 pub fn mp_lock_region_cfg(&self, region_num: usize) -> Result<(), ErrorCode> {
925 if region_num > FlashRegion::REGION7 as usize {
926 return Err(ErrorCode::NOSUPPORT);
927 }
928
929 if !self.registers.region_cfg_regwen[region_num].is_set(REGION_CFG_REGWEN::REGION) {
930 return Err(ErrorCode::ALREADY);
932 }
933
934 self.registers.region_cfg_regwen[region_num].write(REGION_CFG_REGWEN::REGION::Locked);
935
936 Ok(())
937 }
938}
939
940impl<C: hil::flash::Client<Self>> hil::flash::HasClient<'static, C> for FlashCtrl<'_> {
941 fn set_client(&self, client: &'static C) {
942 self.flash_client.set(client);
943 }
944}
945
946impl hil::flash::Flash for FlashCtrl<'_> {
947 type Page = LowRiscPage;
948
949 fn read_page(
952 &self,
953 page_number: usize,
954 buf: &'static mut Self::Page,
955 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
956 if page_number >= FLASH_MAX_PAGES {
957 return Err((ErrorCode::INVAL, buf));
958 }
959
960 let addr = page_number.saturating_mul(PAGE_SIZE);
961
962 if !self.info_configured.get() {
963 if let Err(e) = self.configure_info_partition(FlashBank::BANK1, self.region_num) {
965 return Err((e, buf));
966 }
967 }
968
969 if !self.data_configured.get() {
970 if let Err(e) = self.configure_data_partition(self.region_num) {
972 return Err((e, buf));
973 }
974 }
975
976 self.enable_interrupts();
978 self.registers.fifo_lvl.modify(FIFO_LVL::RD.val(0xF));
979
980 if !self.registers.ctrl_regwen.is_set(CTRL_REGWEN::EN) {
982 return Err((ErrorCode::BUSY, buf));
983 }
984
985 self.read_buf.replace(buf);
987 self.read_index.set(0);
988
989 self.registers.control.write(
991 CONTROL::OP::READ
992 + CONTROL::PARTITION_SEL::DATA
993 + CONTROL::INFO_SEL::SET
994 + CONTROL::NUM.val((FLASH_NUM_BUSWORDS_PER_BANK - 1) as u32)
995 + CONTROL::START::CLEAR,
996 );
997
998 self.registers.addr.write(ADDR::START.val(addr as u32));
1000
1001 self.registers.control.modify(CONTROL::START::SET);
1003
1004 Ok(())
1005 }
1006
1007 fn write_page(
1011 &self,
1012 page_number: usize,
1013 buf: &'static mut Self::Page,
1014 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
1015 if page_number >= FLASH_MAX_PAGES {
1016 return Err((ErrorCode::INVAL, buf));
1017 }
1018 let addr = page_number.saturating_mul(PAGE_SIZE);
1019
1020 if !self.info_configured.get() {
1021 if let Err(e) = self.configure_info_partition(FlashBank::BANK1, self.region_num) {
1024 return Err((e, buf));
1025 }
1026 }
1027
1028 if !self.data_configured.get() {
1029 if let Err(e) = self.configure_data_partition(self.region_num) {
1031 return Err((e, buf));
1032 }
1033 }
1034
1035 if !self.registers.ctrl_regwen.is_set(CTRL_REGWEN::EN) {
1037 return Err((ErrorCode::BUSY, buf));
1038 }
1039
1040 let word_address = addr / 4;
1043
1044 let transaction_word_len =
1045 self.calculate_max_prog_len(word_address as u32, buf.0.len() as u32);
1046
1047 self.registers.control.write(
1048 CONTROL::OP::PROG
1049 + CONTROL::PARTITION_SEL::DATA
1050 + CONTROL::INFO_SEL::CLEAR
1051 + CONTROL::NUM.val(transaction_word_len - 1)
1052 + CONTROL::START::CLEAR,
1053 );
1054
1055 self.registers.addr.write(ADDR::START.val(addr as u32));
1057
1058 self.write_index.set(0);
1060
1061 self.registers.control.modify(CONTROL::START::SET);
1063
1064 let mut words_written = 0;
1065
1066 for i in 0..transaction_word_len {
1068 if self.registers.status.is_set(STATUS::PROG_FULL) {
1069 words_written = i;
1070 break;
1071 }
1072 let buf_offset = self.write_index.get();
1073 let data: u32 = buf[buf_offset] as u32
1074 | (buf[buf_offset + 1] as u32) << 8
1075 | (buf[buf_offset + 2] as u32) << 16
1076 | (buf[buf_offset + 3] as u32) << 24;
1077
1078 self.registers.prog_fifo.set(data);
1079
1080 self.write_index.set(buf_offset + 4);
1081 words_written = i + 1;
1083 }
1084
1085 self.write_word_addr
1086 .set((addr / 4) + words_written as usize);
1087
1088 self.write_buf.replace(buf);
1090
1091 self.enable_interrupts();
1093 self.registers.fifo_lvl.modify(FIFO_LVL::PROG.val(0x00));
1094
1095 Ok(())
1096 }
1097
1098 fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
1102 if page_number >= FLASH_MAX_PAGES {
1103 return Err(ErrorCode::INVAL);
1104 }
1105 let addr = page_number.saturating_mul(PAGE_SIZE);
1106
1107 if !self.data_configured.get() {
1108 self.configure_data_partition(self.region_num)?;
1110 }
1111
1112 if !self.info_configured.get() {
1113 self.configure_info_partition(FlashBank::BANK1, self.region_num)?;
1115 }
1116
1117 if !self.registers.ctrl_regwen.is_set(CTRL_REGWEN::EN) {
1119 return Err(ErrorCode::BUSY);
1120 }
1121
1122 for _ in 0..2 {
1124 self.registers
1125 .mp_bank_cfg_shadowed
1126 .modify(MP_BANK_CFG::ERASE_EN_0::CLEAR + MP_BANK_CFG::ERASE_EN_1::CLEAR);
1127 }
1128
1129 self.registers.addr.write(ADDR::START.val(addr as u32));
1131
1132 self.enable_interrupts();
1134
1135 self.registers.control.write(
1137 CONTROL::OP::ERASE
1138 + CONTROL::ERASE_SEL::PAGE
1139 + CONTROL::PARTITION_SEL::DATA
1140 + CONTROL::START::SET,
1141 );
1142 Ok(())
1143 }
1144}