1use core::cell::Cell;
8use core::ops::{Index, IndexMut};
9use kernel::deferred_call::{DeferredCall, DeferredCallClient};
10use kernel::hil;
11use kernel::utilities::cells::OptionalCell;
12use kernel::utilities::cells::TakeCell;
13use kernel::ErrorCode;
14
15pub const PAGE_SIZE: usize = 8 * 1024;
16pub const FLASH_INSTANCE_SIZE: usize = 512 * 1024;
17pub const FLASH_NUM_INSTANCES: usize = 2;
18pub const FLASH_PAGES_PER_INSTANCE: usize = FLASH_INSTANCE_SIZE / PAGE_SIZE;
19pub const FLASH_MAX_PAGES: usize = FLASH_NUM_INSTANCES * FLASH_PAGES_PER_INSTANCE;
20
21const FLASH_PROGRAM_KEY: u32 = 0x12344321;
22
23#[derive(PartialEq)]
25enum FlashInstance {
26 MAIN0 = 0,
27 MAIN1 = 1,
28}
29
30pub struct Apollo3Page(pub [u8; PAGE_SIZE]);
31
32impl Default for Apollo3Page {
33 fn default() -> Self {
34 Self([0; PAGE_SIZE])
35 }
36}
37
38impl Index<usize> for Apollo3Page {
39 type Output = u8;
40
41 fn index(&self, idx: usize) -> &u8 {
42 &self.0[idx]
43 }
44}
45
46impl IndexMut<usize> for Apollo3Page {
47 fn index_mut(&mut self, idx: usize) -> &mut u8 {
48 &mut self.0[idx]
49 }
50}
51
52impl AsMut<[u8]> for Apollo3Page {
53 fn as_mut(&mut self) -> &mut [u8] {
54 &mut self.0
55 }
56}
57
58unsafe fn flash_util_read_word(addr: *mut u32) -> u32 {
72 let flash_util_read_word: unsafe extern "C" fn(*mut u32) -> u32 =
74 unsafe { core::mem::transmute(0x08000075 as *const ()) };
75
76 flash_util_read_word(addr)
77}
78
79unsafe fn flash_program_main(
105 program_key: u32,
106 src_addr: *mut u32,
107 dst_addr: *mut u32,
108 num_words: u32,
109) -> i32 {
110 use core::ffi::c_int;
111
112 let flash_program_main: unsafe extern "C" fn(u32, *mut u32, *mut u32, u32) -> c_int =
114 unsafe { core::mem::transmute(0x08000055 as *const ()) };
115
116 flash_program_main(program_key, src_addr, dst_addr, num_words)
117}
118
119unsafe fn flash_page_erase(program_key: u32, flash_instance: u32, page_num: u32) -> i32 {
141 use core::ffi::c_int;
142
143 let flash_page_erase: unsafe extern "C" fn(u32, u32, u32) -> c_int =
145 unsafe { core::mem::transmute(0x08000051 as *const ()) };
146
147 flash_page_erase(program_key, flash_instance, page_num)
148}
149
150#[derive(Copy, Clone, PartialEq)]
151enum Operation {
152 None,
153 Read,
154 Write,
155 Erase,
156}
157
158pub struct FlashCtrl<'a> {
159 flash_client: OptionalCell<&'a dyn hil::flash::Client<FlashCtrl<'a>>>,
160 read_buf: TakeCell<'static, Apollo3Page>,
161 write_buf: TakeCell<'static, Apollo3Page>,
162
163 deferred_call: DeferredCall,
164 op: Cell<Operation>,
165}
166
167impl FlashCtrl<'_> {
168 pub fn new() -> Self {
169 FlashCtrl {
170 flash_client: OptionalCell::empty(),
171 read_buf: TakeCell::empty(),
172 write_buf: TakeCell::empty(),
173 deferred_call: DeferredCall::new(),
174 op: Cell::new(Operation::None),
175 }
176 }
177}
178
179impl<C: hil::flash::Client<Self>> hil::flash::HasClient<'static, C> for FlashCtrl<'_> {
180 fn set_client(&self, client: &'static C) {
181 self.flash_client.set(client);
182 }
183}
184
185impl hil::flash::Flash for FlashCtrl<'_> {
186 type Page = Apollo3Page;
187
188 fn read_page(
189 &self,
190 page_number: usize,
191 buf: &'static mut Self::Page,
192 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
193 if page_number >= FLASH_MAX_PAGES {
194 return Err((ErrorCode::INVAL, buf));
195 }
196
197 if self.op.get() != Operation::None {
198 return Err((ErrorCode::BUSY, buf));
199 }
200
201 if self.deferred_call.is_pending() {
202 return Err((ErrorCode::BUSY, buf));
203 }
204
205 let addr = (page_number * PAGE_SIZE) as u32;
206 let addr_ptr = addr as *mut u32;
207
208 for i in 0..(PAGE_SIZE / 4) {
209 let val = unsafe { flash_util_read_word(addr_ptr.wrapping_add(i)).to_le_bytes() };
210 let offset = i * 4;
211
212 buf[offset] = val[0];
213 buf[offset + 1] = val[1];
214 buf[offset + 2] = val[2];
215 buf[offset + 3] = val[3];
216 }
217
218 self.read_buf.replace(buf);
219 self.op.set(Operation::Read);
220 self.deferred_call.set();
221 Ok(())
222 }
223
224 fn write_page(
225 &self,
226 page_number: usize,
227 buf: &'static mut Self::Page,
228 ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
229 if page_number >= FLASH_MAX_PAGES {
230 return Err((ErrorCode::INVAL, buf));
231 }
232
233 if self.op.get() != Operation::None {
234 return Err((ErrorCode::BUSY, buf));
235 }
236
237 if self.deferred_call.is_pending() {
238 return Err((ErrorCode::BUSY, buf));
239 }
240
241 let addr = (page_number * PAGE_SIZE) as u32;
242 let addr_ptr = addr as *mut u32;
243
244 let source_ptr = buf.0.as_mut_ptr() as *mut u32;
245
246 let ret = unsafe {
247 flash_program_main(
248 FLASH_PROGRAM_KEY,
249 source_ptr,
250 addr_ptr,
251 PAGE_SIZE as u32 / 4,
252 )
253 };
254
255 match ret {
256 0 => {
257 self.write_buf.replace(buf);
258 self.op.set(Operation::Write);
259 self.deferred_call.set();
260 Ok(())
261 }
262 1 => {
263 Err((ErrorCode::NOSUPPORT, buf))
265 }
266 2 => {
267 Err((ErrorCode::INVAL, buf))
269 }
270 3 => {
271 Err((ErrorCode::INVAL, buf))
273 }
274 4 => {
275 Err((ErrorCode::INVAL, buf))
277 }
278 6 => {
279 Err((ErrorCode::BUSY, buf))
281 }
282 _ => Err((ErrorCode::FAIL, buf)),
283 }
284 }
285
286 fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
287 if page_number >= FLASH_MAX_PAGES {
288 return Err(ErrorCode::INVAL);
289 }
290
291 if self.op.get() != Operation::None {
292 return Err(ErrorCode::BUSY);
293 }
294
295 if self.deferred_call.is_pending() {
296 return Err(ErrorCode::BUSY);
297 }
298
299 let ret = if page_number <= FLASH_PAGES_PER_INSTANCE {
300 unsafe {
301 flash_page_erase(
302 FLASH_PROGRAM_KEY,
303 FlashInstance::MAIN0 as u32,
304 page_number as u32,
305 )
306 }
307 } else {
308 unsafe {
309 flash_page_erase(
310 FLASH_PROGRAM_KEY,
311 FlashInstance::MAIN1 as u32,
312 (page_number - FLASH_PAGES_PER_INSTANCE) as u32,
313 )
314 }
315 };
316
317 match ret {
318 0 => {
319 self.op.set(Operation::Erase);
320 self.deferred_call.set();
321 Ok(())
322 }
323 1 => {
324 Err(ErrorCode::NOSUPPORT)
326 }
327 2 => {
328 Err(ErrorCode::NOSUPPORT)
330 }
331 3 => {
332 Err(ErrorCode::INVAL)
334 }
335 4 => {
336 Err(ErrorCode::BUSY)
338 }
339 _ => Err(ErrorCode::FAIL),
340 }
341 }
342}
343
344impl DeferredCallClient for FlashCtrl<'_> {
345 fn register(&'static self) {
346 self.deferred_call.register(self);
347 }
348
349 fn handle_deferred_call(&self) {
350 let prev_op = self.op.get();
351
352 self.op.set(Operation::None);
353
354 self.flash_client.map(|client| match prev_op {
355 Operation::None => unreachable!(),
356 Operation::Read => client.read_complete(self.read_buf.take().unwrap(), Ok(())),
357 Operation::Write => client.write_complete(self.write_buf.take().unwrap(), Ok(())),
358 Operation::Erase => client.erase_complete(Ok(())),
359 });
360 }
361}