@@ -2146,34 +2146,45 @@ struct picoboot_memory_access : public memory_access {
2146
2146
vector<uint8_t > write_data; // used when erasing flash
2147
2147
if (flash == get_memory_type (address, model)) {
2148
2148
connection.exit_xip ();
2149
- if (erase) {
2150
- // Do automatically erase flash, and make it aligned
2151
- // we have to erase in whole pages
2152
- range aligned_range (address & ~(FLASH_SECTOR_ERASE_SIZE - 1 ),
2153
- ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1 )) + FLASH_SECTOR_ERASE_SIZE);
2154
- assert (aligned_range.contains (address));
2155
- assert (aligned_range.contains (address + size));
2156
-
2157
- uint32_t pre_len = address - aligned_range.from ;
2158
- uint32_t post_len = aligned_range.to - (address + size);
2159
- assert (pre_len + size + post_len == aligned_range.len ());
2160
-
2161
- // save data before the changing data
2162
- write_data.resize (pre_len);
2163
- if (pre_len) read (aligned_range.from , write_data.data (), write_data.size (), false );
2164
- // now add the data that is changing
2165
- write_data.insert (write_data.end (), buffer, buffer + size);
2166
- // save data after the changing data
2167
- write_data.resize (aligned_range.len ());
2168
- if (post_len) read (address + size, write_data.data () + pre_len + size, post_len, false );
2169
-
2170
- // Do the erase
2171
- connection.flash_erase (aligned_range.from , aligned_range.len ());
2172
-
2173
- // Update what will now be written
2174
- address = aligned_range.from ;
2175
- buffer = write_data.data ();
2176
- size = aligned_range.len ();
2149
+ // Flash Translation Layer - auto-erase, and only write changed data
2150
+ if (enable_ftl) {
2151
+ // Check what's there already
2152
+ write_data.resize (size);
2153
+ read (address, write_data.data (), size, false );
2154
+ // Check if we even need to write
2155
+ if (std::equal (write_data.cbegin (), write_data.cend (), buffer)) {
2156
+ return ;
2157
+ }
2158
+ // Check if we need to erase (ie check for non 0xff)
2159
+ if (!std::all_of (write_data.cbegin (), write_data.cend (), [](uint8_t v) { return v == 0xff ; })) {
2160
+ // Do automatically erase flash, and make it aligned
2161
+ // we have to erase in whole pages
2162
+ range aligned_range (address & ~(FLASH_SECTOR_ERASE_SIZE - 1 ),
2163
+ ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1 )) + FLASH_SECTOR_ERASE_SIZE);
2164
+ assert (aligned_range.contains (address));
2165
+ assert (aligned_range.contains (address + size));
2166
+
2167
+ uint32_t pre_len = address - aligned_range.from ;
2168
+ uint32_t post_len = aligned_range.to - (address + size);
2169
+ assert (pre_len + size + post_len == aligned_range.len ());
2170
+
2171
+ // save data before the changing data
2172
+ write_data.resize (pre_len);
2173
+ if (pre_len) read (aligned_range.from , write_data.data (), write_data.size (), false );
2174
+ // now add the data that is changing
2175
+ write_data.insert (write_data.end (), buffer, buffer + size);
2176
+ // save data after the changing data
2177
+ write_data.resize (aligned_range.len ());
2178
+ if (post_len) read (address + size, write_data.data () + pre_len + size, post_len, false );
2179
+
2180
+ // Do the erase
2181
+ connection.flash_erase (aligned_range.from , aligned_range.len ());
2182
+
2183
+ // Update what will now be written
2184
+ address = aligned_range.from ;
2185
+ buffer = write_data.data ();
2186
+ size = aligned_range.len ();
2187
+ }
2177
2188
}
2178
2189
}
2179
2190
if (is_transfer_aligned (address, model) && is_transfer_aligned (address + size, model)) {
@@ -2192,7 +2203,8 @@ struct picoboot_memory_access : public memory_access {
2192
2203
write (addr, (uint8_t *)v.data (), v.size () * sizeof (typename raw_type_mapping<T>::access_type));
2193
2204
}
2194
2205
2195
- bool erase = false ;
2206
+ // Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2207
+ bool enable_ftl = false ;
2196
2208
private:
2197
2209
picoboot::connection& connection;
2198
2210
vector<std::tuple<uint32_t ,uint32_t ,vector<uint8_t >>> flash_cache;
@@ -4187,7 +4199,7 @@ bool config_command::execute(device_map &devices) {
4187
4199
picoboot::connection connection (std::get<2 >(handles), std::get<0 >(handles));
4188
4200
picoboot_memory_access access (connection);
4189
4201
// Enable auto-erase
4190
- access.erase = true ;
4202
+ access.enable_ftl = true ;
4191
4203
auto partitions = get_partitions (connection);
4192
4204
vector<uint32_t > starts;
4193
4205
if (partitions) {
@@ -5471,7 +5483,12 @@ void setup_bdevfs(picoboot::connection con) {
5471
5483
string s = ss.str ();
5472
5484
fos << " embedded drive: " << s << " \n " ;
5473
5485
5474
- bdevfs_setup.base_addr = bi_bdev.address ;
5486
+ if (bi_bdev.address < FLASH_START) {
5487
+ // Some devices have the block device address relative to the start of flash
5488
+ bdevfs_setup.base_addr = bi_bdev.address + FLASH_START;
5489
+ } else {
5490
+ bdevfs_setup.base_addr = bi_bdev.address ;
5491
+ }
5475
5492
bdevfs_setup.size = bi_bdev.size ;
5476
5493
});
5477
5494
visitor.visit (access, hdr);
@@ -5528,15 +5545,17 @@ DWORD get_fattime (void) {
5528
5545
return fattime;
5529
5546
}
5530
5547
5548
+ static_assert (FF_MAX_SS == FF_MIN_SS, " FF_MAX_SS must be equal to FF_MIN_SS" );
5549
+ #define SECTOR_SIZE FF_MAX_SS
5531
5550
5532
5551
DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count) {
5533
- bdevfs_setup.access ->read (bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t *)buff, count * FF_MAX_SS , false );
5552
+ bdevfs_setup.access ->read (bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t *)buff, count * SECTOR_SIZE , false );
5534
5553
return RES_OK;
5535
5554
}
5536
5555
5537
5556
DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
5538
5557
if (bdevfs_setup.writeable ) {
5539
- bdevfs_setup.access ->write (bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t *)buff, count * FF_MAX_SS );
5558
+ bdevfs_setup.access ->write (bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t *)buff, count * SECTOR_SIZE );
5540
5559
return RES_OK;
5541
5560
} else {
5542
5561
fail (ERROR_NOT_POSSIBLE, " This block device is not writeable" );
@@ -5550,11 +5569,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5550
5569
return RES_OK;
5551
5570
5552
5571
case GET_SECTOR_COUNT:
5553
- *(DWORD*)buff = bdevfs_setup.size / FF_MAX_SS;
5572
+ *(DWORD*)buff = bdevfs_setup.size / SECTOR_SIZE;
5573
+ return RES_OK;
5574
+
5575
+ case GET_SECTOR_SIZE:
5576
+ *(DWORD*)buff = SECTOR_SIZE;
5554
5577
return RES_OK;
5555
5578
5556
5579
case GET_BLOCK_SIZE:
5557
- *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS ;
5580
+ *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE ;
5558
5581
return RES_OK;
5559
5582
5560
5583
case IOCTL_INIT:
@@ -5564,6 +5587,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5564
5587
return RES_OK;
5565
5588
}
5566
5589
5590
+ case CTRL_TRIM: {
5591
+ if (bdevfs_setup.writeable ) {
5592
+ DWORD* p = (DWORD*)buff;
5593
+ uint32_t start = (*p * SECTOR_SIZE) + bdevfs_setup.base_addr ;
5594
+ uint32_t end = (*(p + 1 ) * SECTOR_SIZE) + bdevfs_setup.base_addr ;
5595
+ // Only trim complete flash sectors
5596
+ if (start % FLASH_SECTOR_ERASE_SIZE) start += FLASH_SECTOR_ERASE_SIZE - (start % FLASH_SECTOR_ERASE_SIZE);
5597
+ end -= end % FLASH_SECTOR_ERASE_SIZE;
5598
+ for (uint32_t addr = start; addr < end; addr += FLASH_SECTOR_ERASE_SIZE) {
5599
+ bdevfs_setup.con ->flash_erase (addr, FLASH_SECTOR_ERASE_SIZE);
5600
+ }
5601
+ return RES_OK;
5602
+ } else {
5603
+ fail (ERROR_NOT_POSSIBLE, " This block device is not writeable" );
5604
+ return RES_WRPRT;
5605
+ }
5606
+ }
5607
+
5567
5608
default :
5568
5609
fail (ERROR_NOT_POSSIBLE, " Unknown ioctl %d" , cmd);
5569
5610
return RES_PARERR;
@@ -5635,14 +5676,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
5635
5676
FATFS fatfs;
5636
5677
5637
5678
// Enable auto-erase, as FatFS has no Flash Translation Layer
5638
- bdevfs_setup.access ->erase = true ;
5679
+ bdevfs_setup.access ->enable_ftl = true ;
5639
5680
5640
5681
int err = f_mount (&fatfs);
5641
5682
if (err == FR_NO_FILESYSTEM) {
5642
5683
if (settings.bdev .format ) {
5643
5684
if (bdevfs_setup.formattable ) {
5644
5685
fos << " Formatting FatFS file system\n " ;
5645
- uint8_t work_buf[FF_MAX_SS ];
5686
+ uint8_t work_buf[SECTOR_SIZE ];
5646
5687
err = f_mkfs (&fatfs, FM_ANY | FM_SFD, 0 , work_buf, sizeof (work_buf));
5647
5688
if (err) {
5648
5689
fail (ERROR_CONNECTION, " FatFS Format Error %d" , err);
0 commit comments