14
14
15
15
#include "spi_mem.h"
16
16
#include "bitbox02_pins.h"
17
+ #include "random.h"
18
+ #include "screen.h"
17
19
#include "util.h"
18
20
#include <hal_delay.h>
19
21
#include <spi_lite.h>
24
26
#define SECTOR_MASK 0xFFFFF000
25
27
#define MEMORY_LIMIT (SPI_MEM_MEMORY_SIZE - 1)
26
28
#define SR_WIP 0x01
29
+ #define SR_PROTECT_BITS_MASK 0x3C
30
+ #define SR_PROTECT_BITS_SHIFT 2
31
+ #define SR_PROTECT_BITS (SPI_MEM_PROTECTED_BLOCKS << SR_PROTECT_BITS_SHIFT)
32
+ #define CR1_TB_BIT_BOTTOM 0x8
33
+ #define CR1_TB_BIT_MASK 0x8
27
34
#define CMD_READ 0x03
28
35
#define CMD_WREN 0x06
36
+ #define CMD_WRSR 0x01
29
37
#define CMD_SE 0x20
30
38
#define CMD_PP 0x02
31
39
#define CMD_RDSR 0x05
40
+ #define CMD_RDCR 0x15
32
41
#define CMD_CE 0x60
33
42
43
+ // Drives the chip select pin low
34
44
static void _spi_mem_cs_low (void )
35
45
{
36
46
gpio_set_pin_level (PIN_MEM_CS , 0 );
37
47
}
38
48
49
+ // Drives the chip select pin high
39
50
static void _spi_mem_cs_high (void )
40
51
{
41
52
gpio_set_pin_level (PIN_MEM_CS , 1 );
42
53
}
43
54
55
+ // Reads the status register
44
56
static uint8_t _spi_mem_read_sr (void )
45
57
{
46
58
uint8_t buffer [2 ] = {0 };
@@ -51,19 +63,19 @@ static uint8_t _spi_mem_read_sr(void)
51
63
return buffer [1 ];
52
64
}
53
65
54
- static void _spi_mem_read (uint32_t address , size_t size , uint8_t * buffer )
66
+ // Reads the configuration register
67
+ static void _spi_mem_read_cr (uint8_t * data_out )
55
68
{
56
- buffer [0 ] = CMD_READ ;
57
- buffer [1 ] = (address >> 16 ) & 0xFF ;
58
- buffer [2 ] = (address >> 8 ) & 0xFF ;
59
- buffer [3 ] = address & 0xFF ;
60
- memset (& buffer [4 ], 0x00 , size );
61
-
69
+ uint8_t buffer [3 ] = {0 };
70
+ buffer [0 ] = CMD_RDCR ;
62
71
_spi_mem_cs_low ();
63
- SPI_MEM_exchange_block (buffer , size + 4 );
72
+ SPI_MEM_exchange_block (buffer , 3 );
64
73
_spi_mem_cs_high ();
74
+
75
+ memcpy (data_out , & buffer [1 ], 2 );
65
76
}
66
77
78
+ // Waits until the WIP bits goes low
67
79
static void _spi_mem_wait (void )
68
80
{
69
81
uint8_t status ;
@@ -72,23 +84,67 @@ static void _spi_mem_wait(void)
72
84
} while (status & SR_WIP );
73
85
}
74
86
75
- void spi_mem_full_erase (void )
87
+ // Set write enable bit
88
+ static void _spi_mem_write_enable (void )
89
+ {
90
+ uint8_t cmd = CMD_WREN ;
91
+ _spi_mem_cs_low ();
92
+ SPI_MEM_exchange_block (& cmd , 1 );
93
+ _spi_mem_cs_high ();
94
+ }
95
+
96
+ // Verify if the given address is protected
97
+ static bool _spi_mem_verify_address_protected (uint32_t address )
98
+ {
99
+ uint8_t protected_blocks = (_spi_mem_read_sr () & SR_PROTECT_BITS_MASK ) >> SR_PROTECT_BITS_SHIFT ;
100
+ if (address < (protected_blocks * SPI_MEM_BLOCK_SIZE )) {
101
+ return true;
102
+ }
103
+ return false;
104
+ }
105
+
106
+ // Write the status and configuration registers
107
+ static void _spi_mem_write_sr (uint8_t * data_in )
76
108
{
77
- uint8_t buffer [2 ];
109
+ _spi_mem_write_enable ();
110
+ uint8_t buffer [4 ] = {0 };
111
+ buffer [0 ] = CMD_WRSR ;
112
+ memcpy (& buffer [1 ], data_in , 3 );
113
+ _spi_mem_cs_low ();
114
+ SPI_MEM_exchange_block (buffer , 4 );
115
+ _spi_mem_cs_high ();
116
+ _spi_mem_wait ();
117
+ }
118
+
119
+ // Reads `size` bytes starting from `address` and writes the data into `buffer`
120
+ static void _spi_mem_read (uint32_t address , size_t size , uint8_t * buffer )
121
+ {
122
+ buffer [0 ] = CMD_READ ;
123
+ buffer [1 ] = (address >> 16 ) & 0xFF ;
124
+ buffer [2 ] = (address >> 8 ) & 0xFF ;
125
+ buffer [3 ] = address & 0xFF ;
126
+ memset (& buffer [4 ], 0x00 , size );
78
127
79
- // --- Enable Write ---
80
- buffer [0 ] = CMD_WREN ;
81
128
_spi_mem_cs_low ();
82
- SPI_MEM_exchange_block (buffer , 1 );
129
+ SPI_MEM_exchange_block (buffer , size + 4 );
83
130
_spi_mem_cs_high ();
131
+ }
132
+
133
+ bool spi_mem_full_erase (void )
134
+ {
135
+ if (_spi_mem_read_sr () & SR_PROTECT_BITS_MASK ) {
136
+ util_log ("Cannot erase with protected area locked." );
137
+ return false;
138
+ }
139
+ _spi_mem_write_enable ();
84
140
85
- // --- Chip Erase ---
86
- buffer [0 ] = CMD_CE ;
141
+ uint8_t cmd = CMD_CE ;
87
142
_spi_mem_cs_low ();
88
- SPI_MEM_exchange_block (buffer , 1 );
143
+ SPI_MEM_exchange_block (& cmd , 1 );
89
144
_spi_mem_cs_high ();
90
145
91
146
_spi_mem_wait ();
147
+ return true;
92
148
}
93
149
94
150
bool spi_mem_sector_erase (uint32_t sector_addr )
@@ -97,15 +153,15 @@ bool spi_mem_sector_erase(uint32_t sector_addr)
97
153
util_log ("Invalid sector address %p" , (void * )(uintptr_t )sector_addr );
98
154
return false;
99
155
}
156
+ if (_spi_mem_verify_address_protected (sector_addr )) {
157
+ util_log ("Sector address %p protected" , (void * )(uintptr_t )sector_addr );
158
+ return false;
159
+ }
100
160
101
- uint8_t buffer [SPI_MEM_PAGE_SIZE + 4 ];
102
- // --- Enable Write ---
103
- buffer [0 ] = CMD_WREN ;
104
- _spi_mem_cs_low ();
105
- SPI_MEM_exchange_block (buffer , 1 );
106
- _spi_mem_cs_high ();
161
+ _spi_mem_write_enable ();
107
162
108
163
// --- Sector Erase (write 4 bytes) ---
164
+ uint8_t buffer [SPI_MEM_PAGE_SIZE + 4 ];
109
165
buffer [0 ] = CMD_SE ;
110
166
buffer [1 ] = (sector_addr >> 16 ) & 0xFF ;
111
167
buffer [2 ] = (sector_addr >> 8 ) & 0xFF ;
@@ -156,21 +212,23 @@ uint8_t* spi_mem_read(uint32_t address, size_t size)
156
212
return buffer ;
157
213
}
158
214
215
+ // Writes SPI_MEM_PAGE_SIZE bytes from `input` at `page_addr`
159
216
static bool _spi_mem_page_write (uint32_t page_addr , const uint8_t * input )
160
217
{
161
218
if (page_addr % SPI_MEM_PAGE_SIZE != 0 ) {
162
219
util_log ("Invalid page write address %p" , (void * )(uintptr_t )page_addr );
163
220
return false;
164
221
}
165
222
166
- uint8_t buffer [ SPI_MEM_PAGE_SIZE + 4 ];
167
- // --- Enable Write ---
168
- buffer [ 0 ] = CMD_WREN ;
169
- _spi_mem_cs_low ();
170
- SPI_MEM_exchange_block ( buffer , 1 );
171
- _spi_mem_cs_high ();
223
+ if ( _spi_mem_verify_address_protected ( page_addr )) {
224
+ util_log ( "Page address %p protected" , ( void * )( uintptr_t ) page_addr );
225
+ return false ;
226
+ }
227
+
228
+ _spi_mem_write_enable ();
172
229
173
230
// --- Page Program (write 4 bytes) ---
231
+ uint8_t buffer [SPI_MEM_PAGE_SIZE + 4 ];
174
232
buffer [0 ] = CMD_PP ;
175
233
buffer [1 ] = (page_addr >> 16 ) & 0xFF ;
176
234
buffer [2 ] = (page_addr >> 8 ) & 0xFF ;
@@ -194,6 +252,11 @@ bool spi_mem_write(uint32_t address, const uint8_t* input, size_t size)
194
252
return false;
195
253
}
196
254
255
+ if (_spi_mem_verify_address_protected (address )) {
256
+ util_log ("Address %p protected" , (void * )(uintptr_t )address );
257
+ return false;
258
+ }
259
+
197
260
uint32_t initial_sector_addr = address & SECTOR_MASK ;
198
261
uint32_t final_sector_addr = ((address + size - 1 ) & SECTOR_MASK ) + SPI_MEM_SECTOR_SIZE ;
199
262
uint16_t sectors = (final_sector_addr - initial_sector_addr ) / SPI_MEM_SECTOR_SIZE ;
@@ -250,3 +313,52 @@ int32_t spi_mem_smart_erase(void)
250
313
251
314
return erased_sectors ;
252
315
}
316
+
317
+ // Writes the `protection` bits into the status register and sets the
318
+ // Top/Bottom bit to bottom in the configuration register.
319
+ static void _spi_mem_set_protection (uint8_t protection )
320
+ {
321
+ uint8_t reg [3 ];
322
+ reg [0 ] = _spi_mem_read_sr ();
323
+ _spi_mem_read_cr (& reg [1 ]);
324
+
325
+ // clean and update status register with protection bits
326
+ reg [0 ] &= ~SR_PROTECT_BITS_MASK ;
327
+ reg [0 ] |= protection & SR_PROTECT_BITS_MASK ;
328
+
329
+ // set the top/bottom protection bit.
330
+ // This is an OTP bit,so the write will have an effect
331
+ // only the first time.
332
+ reg [1 ] = reg [1 ] | CR1_TB_BIT_BOTTOM ;
333
+
334
+ _spi_mem_write_sr (reg );
335
+ }
336
+
337
+ void spi_mem_protected_area_lock (void )
338
+ {
339
+ _spi_mem_set_protection (SR_PROTECT_BITS );
340
+ }
341
+
342
+ void spi_mem_protected_area_unlock (void )
343
+ {
344
+ _spi_mem_set_protection (0x0 );
345
+ }
346
+
347
+ bool spi_mem_protected_area_write (uint32_t address , const uint8_t * input , size_t size )
348
+ {
349
+ // Additional assert to simplify debug.
350
+ ASSERT (_spi_mem_verify_address_protected (address + size ));
351
+ if (!_spi_mem_verify_address_protected (address + size )) {
352
+ util_log (
353
+ "Write address %p and size %i outside protected area" ,
354
+ (void * )(uintptr_t )address ,
355
+ (int )size );
356
+ return false;
357
+ }
358
+ uint8_t protection = _spi_mem_read_sr () & SR_PROTECT_BITS_MASK ;
359
+ _spi_mem_set_protection (0x0 );
360
+ bool result = spi_mem_write (address , input , size );
361
+ _spi_mem_set_protection (protection );
362
+
363
+ return result ;
364
+ }
0 commit comments