1
//! ROM SPI flash wrappers and JEDEC capacity decode.
2

            
3
use procmacros::ram;
4

            
5
use super::{ConfigError, Error};
6

            
7
#[repr(C)]
8
struct RomSpiflashChip {
9
    device_id: u32,
10
}
11

            
12
/// ROM-cached JEDEC id (manufacturer in bits 23:16).
13
///
14
/// ESP32 and ESP32-S2 export `g_rom_flashchip` as a BSS symbol. Later chips
15
/// store the same fields behind `rom_spiflash_legacy_data` (IDF exposes the
16
/// old name as a macro).
17
pub(super) fn cached_device_id() -> u32 {
18
    cfg_select! {
19
        any(esp32, esp32s2) => {
20
            unsafe extern "C" {
21
                static g_rom_flashchip: RomSpiflashChip;
22
            }
23
            unsafe { g_rom_flashchip.device_id }
24
        }
25
        _ => {
26
            #[repr(C)]
27
            struct RomSpiflashLegacyData {
28
                chip: RomSpiflashChip,
29
            }
30
            unsafe extern "C" {
31
                static rom_spiflash_legacy_data: *const RomSpiflashLegacyData;
32
            }
33
14
            let data = unsafe { rom_spiflash_legacy_data };
34
14
            if data.is_null() {
35
                0
36
            } else {
37
14
                unsafe { (*data).chip.device_id }
38
            }
39
        }
40
    }
41
}
42

            
43
/// No-response sentinels.
44
///
45
/// `0xFFFF3F` is esptool's raw `RDID` no-response value; `0x3FFFFF` is that
46
/// word after the ROM's manufacturer-first swap.
47
///
48
/// `0x001540EF` is a valid Winbond W25Q16 JEDEC id. It is only rejected on
49
/// ESP32, where the ROM does not run `RDID` and leaves that word as a
50
/// static placeholder until a second-stage bootloader identifies the chip.
51
fn is_unusable_id(id: u32) -> bool {
52
14
    let no_response = matches!(id, 0x0000_0000 | 0x00FF_FFFF | 0x00FF_FF3F | 0x003F_FFFF);
53
    cfg_select! {
54
        esp32 => no_response || id == 0x0015_40EF,
55
        _ => no_response,
56
    }
57
}
58

            
59
#[inline(never)]
60
fn unknown_flash_chip(raw: u32) -> ConfigError {
61
    warn!("unknown cached flash id {:#010x}", raw);
62
    ConfigError::UnknownFlashChip
63
}
64

            
65
/// Decode flash density from a ROM-cached JEDEC id.
66
///
67
/// The ROM stores the id manufacturer-first, which is the reverse of a raw
68
/// `RDID` word. Adesto (`0x1F`) density nibble sits in bits 12:8 in both
69
/// layouts.
70
pub(super) fn capacity_from_cached_id(raw: u32) -> Result<usize, ConfigError> {
71
14
    let id = raw & 0x00FF_FFFF;
72
    if is_unusable_id(id) {
73
        return Err(unknown_flash_chip(raw));
74
    }
75

            
76
    const KB: u32 = 1024;
77
    const MB: u32 = 1024 * KB;
78

            
79
    let manufacturer = (id >> 16) as u8;
80
14
    let size = if manufacturer == 0x1F {
81
        // https://github.com/espressif/esptool/blob/8363cae8eca42ec70e26edfe4d1727549d6ce578/esptool/cmds.py#L55-L98
82
        match ((id >> 8) as u8) & 0x1F {
83
            0x04 => 512 * KB,
84
            0x05 => MB,
85
            0x06 => 2 * MB,
86
14
            0x07 => 4 * MB,
87
            0x08 => 8 * MB,
88
            0x09 => 16 * MB,
89
            _ => return Err(unknown_flash_chip(raw)),
90
        }
91
    } else {
92
14
        match id as u8 {
93
            0x12 => 256 * KB,
94
            0x13 => 512 * KB,
95
            0x14 => MB,
96
            0x15 => 2 * MB,
97
            0x16 => 4 * MB,
98
            0x17 => 8 * MB,
99
            0x18 => 16 * MB,
100
            0x19 => 32 * MB,
101
            0x1A => 64 * MB,
102
            0x1B => 128 * MB,
103
            0x1C => 256 * MB,
104
            0x20 => 64 * MB,
105
            0x21 => 128 * MB,
106
            0x22 => 256 * MB,
107
            0x32 => 256 * KB,
108
            0x33 => 512 * KB,
109
            0x34 => MB,
110
            0x35 => 2 * MB,
111
            0x36 => 4 * MB,
112
            0x37 => 8 * MB,
113
            0x38 => 16 * MB,
114
            0x39 => 32 * MB,
115
            0x3A => 64 * MB,
116
            _ => return Err(unknown_flash_chip(raw)),
117
        }
118
    };
119

            
120
    Ok(size as usize)
121
}
122

            
123
#[inline(always)]
124
fn check_rc(rc: i32) -> Result<(), Error> {
125
541
    if rc == 0 {
126
        Ok(())
127
    } else {
128
3
        decode_rom_error(rc)
129
    }
130
}
131

            
132
/// Must live in RAM: callers run with the flash cache suspended.
133
#[ram]
134
3
fn decode_rom_error(rc: i32) -> Result<(), Error> {
135
3
    match rc {
136
        1 => Err(Error::IoError),
137
        2 => Err(Error::IoTimeout),
138
        other => {
139
            warn!("unexpected flash ROM status {}", other);
140
            Err(Error::Unknown)
141
        }
142
    }
143
3
}
144

            
145
#[inline(always)]
146
pub(super) fn read(src_addr: u32, data: &mut [u32]) -> Result<(), Error> {
147
    check_rc(unsafe {
148
541
        esp_rom_sys::rom::spiflash::esp_rom_spiflash_read(
149
            src_addr,
150
            data.as_mut_ptr(),
151
541
            data.len() as u32 * super::WORD_SIZE,
152
        )
153
    })
154
}
155

            
156
#[inline(always)]
157
pub(super) fn write(dest_addr: u32, data: &[u32]) -> Result<(), Error> {
158
    check_rc(unsafe {
159
7
        esp_rom_sys::rom::spiflash::esp_rom_spiflash_write(
160
            dest_addr,
161
            data.as_ptr(),
162
7
            data.len() as u32 * super::WORD_SIZE,
163
        )
164
    })
165
}
166

            
167
/// Write `len` bytes at `dest_addr` with transparent encryption.
168
///
169
/// `data` must be word-aligned. On ESP32, `dest_addr` and `len` must be
170
/// 32-byte aligned. On later chips, 16/32/64-byte rows are accepted. The
171
/// ROM may encrypt in place.
172
#[inline(always)]
173
pub(super) fn write_encrypted(dest_addr: u32, data: *mut u32, len: u32) -> Result<(), Error> {
174
    check_rc(unsafe {
175
3
        esp_rom_sys::rom::spiflash::esp_rom_spiflash_write_encrypted(dest_addr, data, len)
176
    })
177
}
178

            
179
#[inline(always)]
180
pub(super) fn unlock() -> Result<(), Error> {
181
8
    check_rc(unsafe { esp_rom_sys::rom::spiflash::esp_rom_spiflash_unlock() })
182
}
183

            
184
#[inline(always)]
185
pub(super) fn erase_sector(sector_number: u32) -> Result<(), Error> {
186
10
    check_rc(unsafe { esp_rom_sys::rom::spiflash::esp_rom_spiflash_erase_sector(sector_number) })
187
}
188

            
189
#[inline(always)]
190
pub(super) fn erase_block(block_number: u32) -> Result<(), Error> {
191
    check_rc(unsafe { esp_rom_sys::rom::spiflash::esp_rom_spiflash_erase_block(block_number) })
192
}