Skip to content

Commit a8bd580

Browse files
authored
fix(rfel): spinand write (#36)
new payload generate from xboot's payload Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
1 parent 86412ee commit a8bd580

5 files changed

Lines changed: 122 additions & 33 deletions

File tree

rfel/assets/payloads/spi_d1.bin

12 Bytes
Binary file not shown.

rfel/src/consts.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
pub const SPI_CMD_END: u8 = 0x00;
2+
pub const SPI_CMD_INIT: u8 = 0x01;
3+
pub const SPI_CMD_SELECT: u8 = 0x02;
4+
pub const SPI_CMD_DESELECT: u8 = 0x03;
5+
pub const SPI_CMD_FAST: u8 = 0x04;
6+
pub const SPI_CMD_TXBUF: u8 = 0x05;
7+
pub const SPI_CMD_RXBUF: u8 = 0x06;
8+
pub const SPI_CMD_SPINOR_WAIT: u8 = 0x07;
9+
pub const SPI_CMD_SPINAND_WAIT: u8 = 0x08;
10+
pub const OPCODE_READ_PAGE_TO_CACHE: u8 = 0x13;
11+
pub const OPCODE_READ_PAGE_FROM_CACHE: u8 = 0x03;
12+
pub const OPCODE_WRITE_ENABLE: u8 = 0x06;
13+
pub const OPCODE_BLOCK_ERASE: u8 = 0xd8;
14+
pub const OPCODE_PROGRAM_LOAD: u8 = 0x02;
15+
pub const OPCODE_PROGRAM_EXEC: u8 = 0x10;
16+
pub const OPCODE_RESET: u8 = 0xff;
17+
18+
pub const OPCODE_RDID: u8 = 0x9f;
19+
pub const OPCODE_GET_FEATURE: u8 = 0x0f;
20+
pub const OPCODE_SET_FEATURE: u8 = 0x1f;
21+
pub const FEATURE_PROTECT: u8 = 0xa0;
22+
pub const FEATURE_STATUS: u8 = 0xc0;

rfel/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod chips;
22
pub mod cli;
3+
pub mod consts;
34
pub mod fel;
45
pub mod ops;
56
pub mod progress;

rfel/src/ops/spinand.rs

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,12 @@ use std::fmt;
33
use std::time::{Duration, Instant};
44

55
use crate::chips::Chip;
6+
use crate::consts::*;
67
use crate::fel::Fel;
78
use crate::progress::Progress;
8-
use crate::spi::{self, SpiError, SpiSession};
9+
use crate::spi::{self, Command, SpiError, SpiSession};
910

1011
const WAIT_TIMEOUT: Duration = Duration::from_secs(5);
11-
const OPCODE_RDID: u8 = 0x9f;
12-
const OPCODE_GET_FEATURE: u8 = 0x0f;
13-
const OPCODE_SET_FEATURE: u8 = 0x1f;
14-
const FEATURE_PROTECT: u8 = 0xa0;
15-
const FEATURE_STATUS: u8 = 0xc0;
16-
const OPCODE_READ_PAGE_TO_CACHE: u8 = 0x13;
17-
const OPCODE_READ_PAGE_FROM_CACHE: u8 = 0x03;
18-
const OPCODE_WRITE_ENABLE: u8 = 0x06;
19-
const OPCODE_BLOCK_ERASE: u8 = 0xd8;
20-
const OPCODE_PROGRAM_LOAD: u8 = 0x02;
21-
const OPCODE_PROGRAM_EXEC: u8 = 0x10;
22-
const OPCODE_RESET: u8 = 0xff;
2312

2413
#[derive(Debug)]
2514
pub enum SpinandError {
@@ -125,6 +114,7 @@ pub fn write(
125114
mut progress: Option<&mut Progress>,
126115
) -> SpinandResult<()> {
127116
let mut state = SpinandState::new(chip, fel)?;
117+
state.erase_range(fel, address, address + data.len() as u64, None)?;
128118
let mut processed = 0u64;
129119
let total = data.len() as u64;
130120
println!(
@@ -220,16 +210,13 @@ impl<'chip> SpinandState<'chip> {
220210
fn erase_block(&mut self, fel: &Fel<'_>, address: u64) -> SpinandResult<()> {
221211
let page_size = self.info.page_size as u64;
222212
let pa = u32::try_from(address / page_size).map_err(|_| SpinandError::AddressOverflow)?;
223-
self.write_enable(fel)?;
224-
self.wait_ready(fel)?;
225-
let tx = [
226-
OPCODE_BLOCK_ERASE,
227-
((pa >> 16) & 0xff) as u8,
228-
((pa >> 8) & 0xff) as u8,
229-
(pa & 0xff) as u8,
230-
];
231-
spi::transfer(fel, &self.session, Some(&tx), None)?;
232-
self.wait_ready(fel)
213+
let mut command = Command::new();
214+
command.enable_write();
215+
command.wait_ready_nand();
216+
command.block_erase(pa);
217+
command.wait_ready_nand();
218+
command.exec(fel, &self.session)?;
219+
Ok(())
233220
}
234221

235222
fn read_range_segment(
@@ -301,7 +288,15 @@ impl<'chip> SpinandState<'chip> {
301288
if bytes_left_in_page == 0 {
302289
break;
303290
}
291+
let mut commands = Command::new();
304292
let chunk = data.len().min(bytes_left_in_page).min(self.chunk_limit());
293+
commands.enable_write();
294+
commands.wait_ready_nand();
295+
commands.program_load(&self.session, column as u16, &data[..chunk]);
296+
commands.wait_ready_nand();
297+
commands.program_exec(page);
298+
commands.wait_ready_nand();
299+
commands.exec(fel, &self.session)?;
305300
self.program_load(fel, column as u16, &data[..chunk])?;
306301
self.wait_ready(fel)?;
307302
data = &data[chunk..];
@@ -317,9 +312,6 @@ impl<'chip> SpinandState<'chip> {
317312
break;
318313
}
319314
}
320-
321-
self.program_exec(fel, page)?;
322-
self.wait_ready(fel)?;
323315
}
324316
Ok(())
325317
}
@@ -480,6 +472,7 @@ impl<'chip> SpinandState<'chip> {
480472
Ok(())
481473
}
482474

475+
#[allow(unused)]
483476
fn program_exec(&mut self, fel: &Fel<'_>, page: u32) -> SpinandResult<()> {
484477
let tx = [
485478
OPCODE_PROGRAM_EXEC,

rfel/src/spi.rs

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
use std::fmt;
22

33
use crate::chips::{Chip, ChipError, ChipSpi, SpiContext};
4+
use crate::consts::*;
45
use crate::fel::Fel;
56
use crate::transfer::{read_all, write_all};
67

7-
const SPI_CMD_END: u8 = 0x00;
8-
const SPI_CMD_INIT: u8 = 0x01;
9-
const SPI_CMD_SELECT: u8 = 0x02;
10-
const SPI_CMD_DESELECT: u8 = 0x03;
11-
const SPI_CMD_TXBUF: u8 = 0x05;
12-
const SPI_CMD_RXBUF: u8 = 0x06;
13-
148
#[derive(Debug)]
159
pub enum SpiError {
1610
Chip(ChipError),
@@ -19,6 +13,85 @@ pub enum SpiError {
1913
LengthOverflow,
2014
}
2115

16+
#[derive(Debug)]
17+
pub struct Command {
18+
commands: Vec<u8>,
19+
data: Vec<u8>,
20+
}
21+
22+
impl Command {
23+
pub fn new() -> Self {
24+
Self {
25+
commands: vec![],
26+
data: vec![],
27+
}
28+
}
29+
pub fn wait_ready_nor(&mut self) {
30+
self.commands
31+
.extend_from_slice(&[SPI_CMD_SELECT, SPI_CMD_SPINOR_WAIT, SPI_CMD_DESELECT]);
32+
}
33+
pub fn wait_ready_nand(&mut self) {
34+
self.commands
35+
.extend_from_slice(&[SPI_CMD_SELECT, SPI_CMD_SPINAND_WAIT, SPI_CMD_DESELECT]);
36+
}
37+
pub fn enable_write(&mut self) {
38+
self.commands.extend_from_slice(&[
39+
SPI_CMD_SELECT,
40+
SPI_CMD_FAST,
41+
1,
42+
OPCODE_WRITE_ENABLE,
43+
SPI_CMD_DESELECT,
44+
]);
45+
}
46+
pub fn program_load(&mut self, session: &SpiSession<'_>, column: u16, data: &[u8]) {
47+
let swap_base = session.context.swap_base;
48+
self.data.push(OPCODE_PROGRAM_LOAD);
49+
self.data.push(((column >> 8) & 0xff) as u8);
50+
self.data.push((column & 0xff) as u8);
51+
self.data.extend_from_slice(data);
52+
self.commands.push(SPI_CMD_SELECT);
53+
self.commands.push(SPI_CMD_TXBUF);
54+
self.commands.extend_from_slice(&swap_base.to_le_bytes());
55+
self.commands
56+
.extend_from_slice(&((data.len() + 3) as u32).to_le_bytes());
57+
self.commands.push(SPI_CMD_DESELECT);
58+
}
59+
pub fn program_exec(&mut self, page: u32) {
60+
self.commands.extend_from_slice(&[
61+
SPI_CMD_SELECT,
62+
SPI_CMD_FAST,
63+
4,
64+
OPCODE_PROGRAM_EXEC,
65+
((page >> 16) & 0xff) as u8,
66+
((page >> 8) & 0xff) as u8,
67+
(page & 0xff) as u8,
68+
SPI_CMD_DESELECT,
69+
]);
70+
}
71+
pub fn block_erase(&mut self, pa: u32) {
72+
self.commands.extend_from_slice(&[
73+
SPI_CMD_SELECT,
74+
SPI_CMD_FAST,
75+
4,
76+
OPCODE_BLOCK_ERASE,
77+
((pa >> 16) & 0xff) as u8,
78+
((pa >> 8) & 0xff) as u8,
79+
(pa & 0xff) as u8,
80+
SPI_CMD_DESELECT,
81+
]);
82+
}
83+
pub fn exec(&mut self, fel: &Fel<'_>, session: &SpiSession<'_>) -> Result<(), SpiError> {
84+
let swap_base = session.context.swap_base;
85+
86+
self.commands.push(SPI_CMD_END);
87+
if self.data.len() != 0 {
88+
write_all(fel, swap_base, &self.data[..]);
89+
}
90+
session.run_commands(fel, &self.commands)?;
91+
Ok(())
92+
}
93+
}
94+
2295
impl fmt::Display for SpiError {
2396
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2497
match self {

0 commit comments

Comments
 (0)