@@ -2083,34 +2083,45 @@ struct picoboot_memory_access : public memory_access {
2083
2083
vector<uint8_t > write_data; // used when erasing flash
2084
2084
if (flash == get_memory_type (address, model)) {
2085
2085
connection.exit_xip ();
2086
- if (erase) {
2087
- // Do automatically erase flash, and make it aligned
2088
- // we have to erase in whole pages
2089
- range aligned_range(address & ~(FLASH_SECTOR_ERASE_SIZE - 1),
2090
- ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1)) + FLASH_SECTOR_ERASE_SIZE);
2091
- assert(aligned_range.contains(address));
2092
- assert(aligned_range.contains(address + size));
2093
-
2094
- uint32_t pre_len = address - aligned_range.from;
2095
- uint32_t post_len = aligned_range.to - (address + size);
2096
- assert(pre_len + size + post_len == aligned_range.len());
2097
-
2098
- // save data before the changing data
2099
- write_data.resize(pre_len);
2100
- if (pre_len) read(aligned_range.from, write_data.data(), write_data.size(), false);
2101
- // now add the data that is changing
2102
- write_data.insert(write_data.end(), buffer, buffer + size);
2103
- // save data after the changing data
2104
- write_data.resize(aligned_range.len());
2105
- if (post_len) read(address + size, write_data.data() + pre_len + size, post_len, false);
2106
-
2107
- // Do the erase
2108
- connection.flash_erase(aligned_range.from, aligned_range.len());
2109
-
2110
- // Update what will now be written
2111
- address = aligned_range.from;
2112
- buffer = write_data.data();
2113
- size = aligned_range.len();
2086
+ // Flash Translation Layer - auto-erase, and only write changed data
2087
+ if (enable_ftl) {
2088
+ // Check what's there already
2089
+ write_data.resize (size);
2090
+ read (address, write_data.data (), size, false );
2091
+ // Check if we even need to write
2092
+ if (std::equal (write_data.cbegin (), write_data.cend (), buffer)) {
2093
+ return ;
2094
+ }
2095
+ // Check if we need to erase (ie check for non 0xff)
2096
+ if (!std::all_of (write_data.cbegin (), write_data.cend (), [](uint8_t v) { return v == 0xff ; })) {
2097
+ // Do automatically erase flash, and make it aligned
2098
+ // we have to erase in whole pages
2099
+ range aligned_range (address & ~(FLASH_SECTOR_ERASE_SIZE - 1 ),
2100
+ ((address + size) & ~(FLASH_SECTOR_ERASE_SIZE - 1 )) + FLASH_SECTOR_ERASE_SIZE);
2101
+ assert (aligned_range.contains (address));
2102
+ assert (aligned_range.contains (address + size));
2103
+
2104
+ uint32_t pre_len = address - aligned_range.from ;
2105
+ uint32_t post_len = aligned_range.to - (address + size);
2106
+ assert (pre_len + size + post_len == aligned_range.len ());
2107
+
2108
+ // save data before the changing data
2109
+ write_data.resize (pre_len);
2110
+ if (pre_len) read (aligned_range.from , write_data.data (), write_data.size (), false );
2111
+ // now add the data that is changing
2112
+ write_data.insert (write_data.end (), buffer, buffer + size);
2113
+ // save data after the changing data
2114
+ write_data.resize (aligned_range.len ());
2115
+ if (post_len) read (address + size, write_data.data () + pre_len + size, post_len, false );
2116
+
2117
+ // Do the erase
2118
+ connection.flash_erase (aligned_range.from , aligned_range.len ());
2119
+
2120
+ // Update what will now be written
2121
+ address = aligned_range.from ;
2122
+ buffer = write_data.data ();
2123
+ size = aligned_range.len ();
2124
+ }
2114
2125
}
2115
2126
}
2116
2127
if (is_transfer_aligned (address, model) && is_transfer_aligned (address + size, model)) {
@@ -2128,7 +2139,8 @@ struct picoboot_memory_access : public memory_access {
2128
2139
write (addr, (uint8_t *)v.data (), v.size () * sizeof (typename raw_type_mapping<T>::access_type));
2129
2140
}
2130
2141
2131
- bool erase = false;
2142
+ // Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2143
+ bool enable_ftl = false ;
2132
2144
private:
2133
2145
picoboot::connection& connection;
2134
2146
};
@@ -4122,7 +4134,7 @@ bool config_command::execute(device_map &devices) {
4122
4134
picoboot::connection connection (std::get<2 >(handles), std::get<0 >(handles));
4123
4135
picoboot_memory_access access (connection);
4124
4136
// Enable auto-erase
4125
- access.erase = true;
4137
+ access .enable_ftl = true ;
4126
4138
auto partitions = get_partitions (connection);
4127
4139
vector<uint32_t > starts;
4128
4140
if (partitions) {
@@ -5395,7 +5407,12 @@ void setup_bdevfs(picoboot::connection con) {
5395
5407
string s = ss.str ();
5396
5408
fos << " embedded drive: " << s << " \n " ;
5397
5409
5398
- bdevfs_setup.base_addr = bi_bdev.address;
5410
+ if (bi_bdev.address < FLASH_START) {
5411
+ // Some devices have the block device address relative to the start of flash
5412
+ bdevfs_setup.base_addr = bi_bdev.address + FLASH_START;
5413
+ } else {
5414
+ bdevfs_setup.base_addr = bi_bdev.address ;
5415
+ }
5399
5416
bdevfs_setup.size = bi_bdev.size ;
5400
5417
});
5401
5418
visitor.visit (access , hdr);
@@ -5452,15 +5469,17 @@ DWORD get_fattime (void) {
5452
5469
return fattime;
5453
5470
}
5454
5471
5472
+ static_assert (FF_MAX_SS == FF_MIN_SS, " FF_MAX_SS must be equal to FF_MIN_SS" );
5473
+ #define SECTOR_SIZE FF_MAX_SS
5455
5474
5456
5475
DRESULT disk_read (void *drv, BYTE* buff, DWORD sector, UINT count) {
5457
- bdevfs_setup.access->read(bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t*)buff, count * FF_MAX_SS , false);
5476
+ bdevfs_setup.access ->read (bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t *)buff, count * SECTOR_SIZE , false );
5458
5477
return RES_OK;
5459
5478
}
5460
5479
5461
5480
DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
5462
5481
if (bdevfs_setup.writeable ) {
5463
- bdevfs_setup.access->write(bdevfs_setup.base_addr + (sector * FF_MAX_SS ), (uint8_t*)buff, count * FF_MAX_SS );
5482
+ bdevfs_setup.access ->write (bdevfs_setup.base_addr + (sector * SECTOR_SIZE ), (uint8_t *)buff, count * SECTOR_SIZE );
5464
5483
return RES_OK;
5465
5484
} else {
5466
5485
fail (ERROR_NOT_POSSIBLE, " This block device is not writeable" );
@@ -5474,11 +5493,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5474
5493
return RES_OK;
5475
5494
5476
5495
case GET_SECTOR_COUNT:
5477
- *(DWORD*)buff = bdevfs_setup.size / FF_MAX_SS;
5496
+ *(DWORD*)buff = bdevfs_setup.size / SECTOR_SIZE;
5497
+ return RES_OK;
5498
+
5499
+ case GET_SECTOR_SIZE:
5500
+ *(DWORD*)buff = SECTOR_SIZE;
5478
5501
return RES_OK;
5479
5502
5480
5503
case GET_BLOCK_SIZE:
5481
- *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS ;
5504
+ *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE ;
5482
5505
return RES_OK;
5483
5506
5484
5507
case IOCTL_INIT:
@@ -5488,6 +5511,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
5488
5511
return RES_OK;
5489
5512
}
5490
5513
5514
+ case CTRL_TRIM: {
5515
+ if (bdevfs_setup.writeable ) {
5516
+ DWORD* p = (DWORD*)buff;
5517
+ uint32_t start = (*p * SECTOR_SIZE) + bdevfs_setup.base_addr ;
5518
+ uint32_t end = (*(p + 1 ) * SECTOR_SIZE) + bdevfs_setup.base_addr ;
5519
+ // Only trim complete flash sectors
5520
+ if (start % FLASH_SECTOR_ERASE_SIZE) start += FLASH_SECTOR_ERASE_SIZE - (start % FLASH_SECTOR_ERASE_SIZE);
5521
+ end -= end % FLASH_SECTOR_ERASE_SIZE;
5522
+ for (uint32_t addr = start; addr < end; addr += FLASH_SECTOR_ERASE_SIZE) {
5523
+ bdevfs_setup.con ->flash_erase (addr, FLASH_SECTOR_ERASE_SIZE);
5524
+ }
5525
+ return RES_OK;
5526
+ } else {
5527
+ fail (ERROR_NOT_POSSIBLE, " This block device is not writeable" );
5528
+ return RES_WRPRT;
5529
+ }
5530
+ }
5531
+
5491
5532
default :
5492
5533
fail (ERROR_NOT_POSSIBLE, " Unknown ioctl %d" , cmd);
5493
5534
return RES_PARERR;
@@ -5559,14 +5600,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
5559
5600
FATFS fatfs;
5560
5601
5561
5602
// Enable auto-erase, as FatFS has no Flash Translation Layer
5562
- bdevfs_setup.access->erase = true;
5603
+ bdevfs_setup.access ->enable_ftl = true ;
5563
5604
5564
5605
int err = f_mount (&fatfs);
5565
5606
if (err == FR_NO_FILESYSTEM) {
5566
5607
if (settings.bdev .format ) {
5567
5608
if (bdevfs_setup.formattable ) {
5568
5609
fos << " Formatting FatFS file system\n " ;
5569
- uint8_t work_buf[FF_MAX_SS ];
5610
+ uint8_t work_buf[SECTOR_SIZE ];
5570
5611
err = f_mkfs (&fatfs, FM_ANY | FM_SFD, 0 , work_buf, sizeof (work_buf));
5571
5612
if (err) {
5572
5613
fail (ERROR_CONNECTION, " FatFS Format Error %d" , err);
0 commit comments