pebble/tests/fakes/fake_flash_region.c
2025-01-27 11:38:16 -08:00

77 lines
3 KiB
C

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "drivers/flash.h"
#include "flash_region/flash_region.h"
#include <stdint.h>
static void prv_erase_optimal_range(uint32_t min_start, uint32_t max_start,
uint32_t min_end, uint32_t max_end) {
// We want to erase the sector that starts immediately below max_start but after min_start. If no sector
// boundary exists between the two, we need to start erasing sectors after min_start and backfill with
// subsector erases.
int32_t sector_start = (max_start & SECTOR_ADDR_MASK);
int32_t subsector_start = (max_start & SUBSECTOR_ADDR_MASK);
if (sector_start < (int32_t) min_start) {
sector_start += SECTOR_SIZE_BYTES;
}
// We want to erase ending after min_end but before max_end. If that ends running past the end of max_end,
// we need to erase starting with the sector before and fill in with subsector erases.
int32_t sector_end = ((min_end - 1) & SECTOR_ADDR_MASK) + SECTOR_SIZE_BYTES;
int32_t subsector_end = ((min_end - 1) & SUBSECTOR_ADDR_MASK) + SUBSECTOR_SIZE_BYTES;
if (sector_end > (int32_t) max_end) {
sector_end -= SECTOR_SIZE_BYTES;
}
int erase_count = 0;
// Do the upkeep immediately just in case we've spent awhile running without feeding the
// watchdog before doing this erase operation.
if (sector_start < sector_end) {
// Now erase the leading subsectors...
for (int32_t i = subsector_start; i < sector_start; i += SUBSECTOR_SIZE_BYTES) {
flash_erase_subsector_blocking(i);
}
// Erase the full sectors...
for (int32_t i = sector_start; i < sector_end; i += SECTOR_SIZE_BYTES) {
flash_erase_sector_blocking(i);
}
// Erase the trailing subsectors
for (int32_t i = sector_end; i < subsector_end; i += SUBSECTOR_SIZE_BYTES) {
flash_erase_subsector_blocking(i);
}
} else {
// Can't erase any full sectors, just erase subsectors the whole way.
for (int32_t i = subsector_start; i < subsector_end; i += SUBSECTOR_SIZE_BYTES) {
flash_erase_subsector_blocking(i);
}
}
}
void flash_region_erase_optimal_range(uint32_t min_start, uint32_t max_start,
uint32_t min_end, uint32_t max_end) {
prv_erase_optimal_range(min_start, max_start, min_end, max_end);
}
void flash_region_erase_optimal_range_no_watchdog(uint32_t min_start, uint32_t max_start,
uint32_t min_end, uint32_t max_end) {
prv_erase_optimal_range(min_start, max_start, min_end, max_end);
}