1use crate::driver::spi::{Result, Spi};
4use core::marker::PhantomData;
5
6pub const SPIF_PAGE_SIZE: usize = 0x100;
7pub const SPIF_SECTOR_SIZE: usize = 0x1000;
8pub const SPIF_BLOCK_SIZE: usize = 0x10000;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Manufacturer {
13 Error = 0,
14 Winbond = 0xEF,
15 ISSI = 0x9D,
16 Micron = 0x20,
17 GigaDevice = 0xC8,
18 Macronix = 0xC2,
19 Spansion = 0x01,
20 Amic = 0x37,
21 Sst = 0xBF,
22 Hyundai = 0xAD,
23 Atmel = 0x1F,
24 Fudan = 0xA1,
25 Esmt = 0x8C,
26 Intel = 0x89,
27 Sanyo = 0x62,
28 Fujitsu = 0x04,
29 Eon = 0x1C,
30 Puya = 0x85,
31 Unknown = 0xFF,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum FlashSize {
36 Error = 0,
37 M1bit = 0x11,
38 M2bit = 0x12,
39 M4bit = 0x13,
40 M8bit = 0x14,
41 M16bit = 0x15,
42 M32bit = 0x16,
43 M64bit = 0x17,
44 M128bit = 0x18,
45 M256bit = 0x19,
46 M512bit = 0x20,
47 Unknown = 0xFF,
48}
49
50pub struct SpiFlash<'a, SPI: Spi<'a>> {
52 spi: SPI,
53 cs: fn(active: bool), pub manufacturer: Manufacturer,
55 pub size: FlashSize,
56 pub page_count: u32,
57 pub sector_count: u32,
58 pub block_count: u32,
59 four_byte_addr: bool,
60 busy: bool,
61 _phantom: PhantomData<&'a ()>,
62}
63
64impl<'a, SPI: Spi<'a>> SpiFlash<'a, SPI> {
65 pub fn new(spi: SPI, cs: fn(active: bool)) -> Self {
66 Self {
67 spi,
68 cs,
69 manufacturer: Manufacturer::Unknown,
70 size: FlashSize::Unknown,
71 page_count: 0,
72 sector_count: 0,
73 block_count: 0,
74 four_byte_addr: false,
75 busy: false,
76 _phantom: PhantomData,
77 }
78 }
79
80 fn select(&self) {
82 (self.cs)(false);
83 }
84 fn deselect(&self) {
86 (self.cs)(true);
87 }
88
89 fn cmd(
91 &mut self,
92 cmd: u8,
93 addr: Option<u32>,
94 tx_data: Option<&[u8]>,
95 rx_data: Option<&mut [u8]>,
96 ) -> Result<()> {
97 let mut buf = [0u8; 5];
98 let mut n = 1;
99 buf[0] = cmd;
100 if let Some(a) = addr {
101 if self.four_byte_addr {
102 buf[1] = ((a >> 24) & 0xFF) as u8;
103 buf[2] = ((a >> 16) & 0xFF) as u8;
104 buf[3] = ((a >> 8) & 0xFF) as u8;
105 buf[4] = (a & 0xFF) as u8;
106 n += 4;
107 } else {
108 buf[1] = ((a >> 16) & 0xFF) as u8;
109 buf[2] = ((a >> 8) & 0xFF) as u8;
110 buf[3] = (a & 0xFF) as u8;
111 n += 3;
112 }
113 }
114 self.select();
115 self.spi.send(&buf[0..n])?;
116 if let Some(tx) = tx_data {
117 self.spi.send(tx)?;
118 }
119 if let Some(rx) = rx_data {
120 self.spi.receive(rx)?;
121 }
122 self.deselect();
123 Ok(())
124 }
125
126 pub fn find_chip(&mut self) -> Result<()> {
127 let mut rx = [0xFFu8; 4];
128 self.select();
129 self.spi.send(&[0x9F])?;
130 self.spi.receive(&mut rx[1..4])?;
131 self.deselect();
132
133 self.manufacturer = match rx[1] {
134 0xEF => Manufacturer::Winbond,
135 0x9D => Manufacturer::ISSI,
136 0x20 => Manufacturer::Micron,
137 0xC8 => Manufacturer::GigaDevice,
138 0xC2 => Manufacturer::Macronix,
139 0x01 => Manufacturer::Spansion,
140 0x37 => Manufacturer::Amic,
141 0xBF => Manufacturer::Sst,
142 0xAD => Manufacturer::Hyundai,
143 0x1F => Manufacturer::Atmel,
144 0xA1 => Manufacturer::Fudan,
145 0x8C => Manufacturer::Esmt,
146 0x89 => Manufacturer::Intel,
147 0x62 => Manufacturer::Sanyo,
148 0x04 => Manufacturer::Fujitsu,
149 0x1C => Manufacturer::Eon,
150 0x85 => Manufacturer::Puya,
151 _ => Manufacturer::Error,
152 };
153 self.size = match rx[3] {
154 0x11 => FlashSize::M1bit,
155 0x12 => FlashSize::M2bit,
156 0x13 => FlashSize::M4bit,
157 0x14 => FlashSize::M8bit,
158 0x15 => FlashSize::M16bit,
159 0x16 => FlashSize::M32bit,
160 0x17 => FlashSize::M64bit,
161 0x18 => FlashSize::M128bit,
162 0x19 => FlashSize::M256bit,
163 0x20 => FlashSize::M512bit,
164 _ => FlashSize::Error,
165 };
166 self.block_count = match self.size {
167 FlashSize::M1bit => 2,
168 FlashSize::M2bit => 4,
169 FlashSize::M4bit => 8,
170 FlashSize::M8bit => 16,
171 FlashSize::M16bit => 32,
172 FlashSize::M32bit => 64,
173 FlashSize::M64bit => 128,
174 FlashSize::M128bit => 256,
175 FlashSize::M256bit => 512,
176 FlashSize::M512bit => 1024,
177 _ => 0,
178 };
179 self.sector_count = self.block_count * 16;
180 self.page_count = self.sector_count * (SPIF_SECTOR_SIZE as u32 / SPIF_PAGE_SIZE as u32);
181 self.four_byte_addr = self.block_count >= 512;
182 Ok(())
183 }
184
185 fn write_enable(&mut self) -> Result<()> {
186 self.cmd(0x06, None, None, None)
187 }
188
189 fn write_disable(&mut self) -> Result<()> {
190 self.cmd(0x04, None, None, None)
191 }
192
193 fn read_status(&mut self) -> Result<u8> {
194 let mut tx = [0x05, 0xA5];
195 let mut rx = [0u8; 2];
196 self.select();
197 self.spi.transfer(&tx, &mut rx)?;
198 self.deselect();
199 Ok(rx[1])
200 }
201
202 pub fn wait_ready(&mut self, timeout: u32, mut delay: impl FnMut(u32)) -> Result<()> {
203 let mut t = 0;
204 while t < timeout {
205 if self.read_status()? & 0x01 == 0 {
206 return Ok(());
207 }
208 delay(1);
209 t += 1;
210 }
211 Err(-1)
212 }
213
214 pub fn erase_chip(&mut self, mut delay: impl FnMut(u32)) -> Result<()> {
215 self.busy = true;
216 self.write_enable()?;
217 self.cmd(0x60, None, None, None)?; self.wait_ready(self.block_count * 1000, &mut delay)?;
219 self.write_disable()?;
220 self.busy = false;
221 Ok(())
222 }
223
224 pub fn erase_sector(&mut self, sector: u32, mut delay: impl FnMut(u32)) -> Result<()> {
225 if sector >= self.sector_count {
226 return Err(-2);
227 }
228 self.busy = true;
229 let address = sector * SPIF_SECTOR_SIZE as u32;
230 self.write_enable()?;
231 self.cmd(
232 if self.four_byte_addr { 0x21 } else { 0x20 },
233 Some(address),
234 None,
235 None,
236 )?;
237 self.wait_ready(1000, &mut delay)?;
238 self.write_disable()?;
239 self.busy = false;
240 Ok(())
241 }
242
243 pub fn erase_block(&mut self, block: u32, mut delay: impl FnMut(u32)) -> Result<()> {
244 if block >= self.block_count {
245 return Err(-2);
246 }
247 self.busy = true;
248 let address = block * SPIF_BLOCK_SIZE as u32;
249 self.write_enable()?;
250 self.cmd(
251 if self.four_byte_addr { 0xDC } else { 0xD8 },
252 Some(address),
253 None,
254 None,
255 )?;
256 self.wait_ready(3000, &mut delay)?;
257 self.write_disable()?;
258 self.busy = false;
259 Ok(())
260 }
261
262 pub fn write_address(
264 &mut self,
265 mut address: u32,
266 mut data: &[u8],
267 mut delay: impl FnMut(u32),
268 ) -> Result<()> {
269 self.busy = true;
270 while !data.is_empty() {
271 let page = (address / SPIF_PAGE_SIZE as u32) as u32;
272 let offset = (address % SPIF_PAGE_SIZE as u32) as usize;
273 let max = SPIF_PAGE_SIZE - offset;
274 let to_write = core::cmp::min(data.len(), max);
275 self.write_page(page, &data[..to_write], offset, &mut delay)?;
276 address += to_write as u32;
277 data = &data[to_write..];
278 }
279 self.busy = false;
280 Ok(())
281 }
282
283 pub fn write_page(
285 &mut self,
286 page: u32,
287 data: &[u8],
288 offset: usize,
289 delay: &mut impl FnMut(u32),
290 ) -> Result<()> {
291 if offset >= SPIF_PAGE_SIZE {
292 return Err(-3);
293 }
294 let n = core::cmp::min(data.len(), SPIF_PAGE_SIZE - offset);
295 let address = page * SPIF_PAGE_SIZE as u32 + offset as u32;
296 self.write_enable()?;
297 self.cmd(
298 if self.four_byte_addr { 0x12 } else { 0x02 },
299 Some(address),
300 Some(&data[..n]),
301 None,
302 )?;
303 self.wait_ready(100, delay)?;
304 self.write_disable()?;
305 Ok(())
306 }
307
308 pub fn read_address(&mut self, mut address: u32, mut data: &mut [u8]) -> Result<()> {
310 self.busy = true;
311 let max_len = 256; let mut off = 0;
313 while off < data.len() {
314 let sz = core::cmp::min(max_len, data.len() - off);
315 self.cmd(
316 if self.four_byte_addr { 0x13 } else { 0x03 },
317 Some(address + off as u32),
318 None,
319 Some(&mut data[off..off + sz]),
320 )?;
321 off += sz;
322 }
323 self.busy = false;
324 Ok(())
325 }
326
327 pub fn read_page(&mut self, page: u32, data: &mut [u8], offset: usize) -> Result<()> {
329 let max = SPIF_PAGE_SIZE - offset;
330 let sz = core::cmp::min(data.len(), max);
331 let address = page * SPIF_PAGE_SIZE as u32 + offset as u32;
332 self.read_address(address, &mut data[..sz])
333 }
334
335 pub fn write_sector(
336 &mut self,
337 sector: u32,
338 data: &[u8],
339 offset: usize,
340 mut delay: impl FnMut(u32),
341 ) -> Result<()> {
342 if offset >= SPIF_SECTOR_SIZE {
343 return Err(-3);
344 }
345 let mut written = 0;
346 let mut page = sector * (SPIF_SECTOR_SIZE as u32 / SPIF_PAGE_SIZE as u32);
347 page += (offset as u32) / SPIF_PAGE_SIZE as u32;
348 let mut rem = core::cmp::min(data.len(), SPIF_SECTOR_SIZE - offset);
349 let mut page_offset = offset % SPIF_PAGE_SIZE;
350 while rem > 0 && page < ((sector + 1) * (SPIF_SECTOR_SIZE as u32 / SPIF_PAGE_SIZE as u32)) {
351 let n = core::cmp::min(SPIF_PAGE_SIZE - page_offset, rem);
352 self.write_page(page, &data[written..written + n], page_offset, &mut delay)?;
353 written += n;
354 rem -= n;
355 page += 1;
356 page_offset = 0;
357 }
358 Ok(())
359 }
360
361 pub fn read_sector(&mut self, sector: u32, data: &mut [u8], offset: usize) -> Result<()> {
362 if offset >= SPIF_SECTOR_SIZE {
363 return Err(-3);
364 }
365 let n = core::cmp::min(data.len(), SPIF_SECTOR_SIZE - offset);
366 let address = sector * SPIF_SECTOR_SIZE as u32 + offset as u32;
367 self.read_address(address, &mut data[..n])
368 }
369
370 pub fn write_block(
371 &mut self,
372 block: u32,
373 data: &[u8],
374 offset: usize,
375 mut delay: impl FnMut(u32),
376 ) -> Result<()> {
377 if offset >= SPIF_BLOCK_SIZE {
378 return Err(-3);
379 }
380 let mut written = 0;
381 let mut page = block * (SPIF_BLOCK_SIZE as u32 / SPIF_PAGE_SIZE as u32);
382 page += (offset as u32) / SPIF_PAGE_SIZE as u32;
383 let mut rem = core::cmp::min(data.len(), SPIF_BLOCK_SIZE - offset);
384 let mut page_offset = offset % SPIF_PAGE_SIZE;
385 while rem > 0 && page < ((block + 1) * (SPIF_BLOCK_SIZE as u32 / SPIF_PAGE_SIZE as u32)) {
386 let n = core::cmp::min(SPIF_PAGE_SIZE - page_offset, rem);
387 self.write_page(page, &data[written..written + n], page_offset, &mut delay)?;
388 written += n;
389 rem -= n;
390 page += 1;
391 page_offset = 0;
392 }
393 Ok(())
394 }
395
396 pub fn read_block(&mut self, block: u32, data: &mut [u8], offset: usize) -> Result<()> {
397 if offset >= SPIF_BLOCK_SIZE {
398 return Err(-3);
399 }
400 let n = core::cmp::min(data.len(), SPIF_BLOCK_SIZE - offset);
401 let address = block * SPIF_BLOCK_SIZE as u32 + offset as u32;
402 self.read_address(address, &mut data[..n])
403 }
404
405 pub fn is_busy(&self) -> bool {
406 self.busy
407 }
408}