@@ -2083,34 +2083,45 @@ struct picoboot_memory_access : public memory_access {
20832083 vector<uint8_t > write_data; // used when erasing flash
20842084 if (flash == get_memory_type (address, model)) {
20852085 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+ }
21142125 }
21152126 }
21162127 if (is_transfer_aligned (address, model) && is_transfer_aligned (address + size, model)) {
@@ -2128,7 +2139,8 @@ struct picoboot_memory_access : public memory_access {
21282139 write (addr, (uint8_t *)v.data (), v.size () * sizeof (typename raw_type_mapping<T>::access_type));
21292140 }
21302141
2131- bool erase = false ;
2142+ // Enable Flash Translation Layer, which performs automatic erase, and only writes changed data
2143+ bool enable_ftl = false ;
21322144private:
21332145 picoboot::connection& connection;
21342146};
@@ -4122,7 +4134,7 @@ bool config_command::execute(device_map &devices) {
41224134 picoboot::connection connection (std::get<2 >(handles), std::get<0 >(handles));
41234135 picoboot_memory_access access (connection);
41244136 // Enable auto-erase
4125- access.erase = true ;
4137+ access.enable_ftl = true ;
41264138 auto partitions = get_partitions (connection);
41274139 vector<uint32_t > starts;
41284140 if (partitions) {
@@ -5395,7 +5407,12 @@ void setup_bdevfs(picoboot::connection con) {
53955407 string s = ss.str ();
53965408 fos << " embedded drive: " << s << " \n " ;
53975409
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+ }
53995416 bdevfs_setup.size = bi_bdev.size ;
54005417 });
54015418 visitor.visit (access, hdr);
@@ -5452,15 +5469,17 @@ DWORD get_fattime (void) {
54525469 return fattime;
54535470}
54545471
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
54555474
54565475DRESULT 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 );
54585477 return RES_OK;
54595478}
54605479
54615480DRESULT disk_write (void *drv, const BYTE* buff, DWORD sector, UINT count) {
54625481 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 );
54645483 return RES_OK;
54655484 } else {
54665485 fail (ERROR_NOT_POSSIBLE, " This block device is not writeable" );
@@ -5474,11 +5493,15 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
54745493 return RES_OK;
54755494
54765495 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;
54785501 return RES_OK;
54795502
54805503 case GET_BLOCK_SIZE:
5481- *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / FF_MAX_SS ;
5504+ *(DWORD*)buff = FLASH_SECTOR_ERASE_SIZE / SECTOR_SIZE ;
54825505 return RES_OK;
54835506
54845507 case IOCTL_INIT:
@@ -5488,6 +5511,24 @@ DRESULT disk_ioctl (void *drv, BYTE cmd, void* buff) {
54885511 return RES_OK;
54895512 }
54905513
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+
54915532 default :
54925533 fail (ERROR_NOT_POSSIBLE, " Unknown ioctl %d" , cmd);
54935534 return RES_PARERR;
@@ -5559,14 +5600,14 @@ void do_fatfs_op(fatfs_op_fn fatfs_op) {
55595600 FATFS fatfs;
55605601
55615602 // Enable auto-erase, as FatFS has no Flash Translation Layer
5562- bdevfs_setup.access ->erase = true ;
5603+ bdevfs_setup.access ->enable_ftl = true ;
55635604
55645605 int err = f_mount (&fatfs);
55655606 if (err == FR_NO_FILESYSTEM) {
55665607 if (settings.bdev .format ) {
55675608 if (bdevfs_setup.formattable ) {
55685609 fos << " Formatting FatFS file system\n " ;
5569- uint8_t work_buf[FF_MAX_SS ];
5610+ uint8_t work_buf[SECTOR_SIZE ];
55705611 err = f_mkfs (&fatfs, FM_ANY | FM_SFD, 0 , work_buf, sizeof (work_buf));
55715612 if (err) {
55725613 fail (ERROR_CONNECTION, " FatFS Format Error %d" , err);
0 commit comments