1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-25 17:25:18 +03:00
inav/src/main/drivers/flash.c
2020-05-09 17:09:16 +02:00

292 lines
6.9 KiB
C

/*
* This file is part of iNav.
*
* iNav is free software. You can redistribute
* this software and/or modify this software under the terms of the
* GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* iNav is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "platform.h"
#include "build/debug.h"
#ifdef USE_FLASHFS
#include "flash.h"
#include "flash_m25p16.h"
#include "drivers/bus_spi.h"
#include "drivers/io.h"
#include "drivers/time.h"
static flashPartitionTable_t flashPartitionTable;
static int flashPartitions = 0;
#ifdef USE_SPI
static bool flashSpiInit(void)
{
#ifdef USE_FLASH_M25P16
return m25p16_init(0);
#endif
return false;
}
#endif // USE_SPI
bool flashDeviceInit(void)
{
#ifdef USE_SPI
return flashSpiInit();
#endif
return false;
}
bool flashIsReady(void)
{
#ifdef USE_FLASH_M25P16
return m25p16_isReady();
#endif
return false;
}
bool flashWaitForReady(uint32_t timeoutMillis)
{
#ifdef USE_FLASH_M25P16
return m25p16_waitForReady(timeoutMillis);
#endif
return false;
}
void flashEraseSector(uint32_t address)
{
#ifdef USE_FLASH_M25P16
return m25p16_eraseSector(address);
#endif
}
void flashEraseCompletely(void)
{
#ifdef USE_FLASH_M25P16
return m25p16_eraseCompletely();
#endif
}
#if 0
void flashPageProgramBegin(uint32_t address)
{
#ifdef USE_FLASH_M25P16
return m25p16_pageProgramBegin(address);
#endif
}
void flashPageProgramContinue(const uint8_t *data, int length)
{
#ifdef USE_FLASH_M25P16
return m25p16_pageProgramContinue(data, length);
#endif
}
void flashPageProgramFinish(void)
{
#ifdef USE_FLASH_M25P16
return m25p16_pageProgramFinish();
#endif
}
#endif
uint32_t flashPageProgram(uint32_t address, const uint8_t *data, int length)
{
#ifdef USE_FLASH_M25P16
return m25p16_pageProgram(address, data, length);
#endif
}
int flashReadBytes(uint32_t address, uint8_t *buffer, int length)
{
#ifdef USE_FLASH_M25P16
return m25p16_readBytes(address, buffer, length);
#endif
return 0;
}
void flashFlush(void)
{
}
const flashGeometry_t *flashGetGeometry(void)
{
#ifdef USE_FLASH_M25P16
return m25p16_getGeometry();
#endif
return NULL;
}
/*
* Flash partitioning
*
* Partition table is not currently stored on the flash, in-memory only.
*
* Partitions are required so that Badblock management (inc spare blocks), FlashFS (Blackbox Logging), Configuration and Firmware can be kept separate and tracked.
*
* XXX FIXME
* XXX Note that Flash FS must start at sector 0.
* XXX There is existing blackbox/flash FS code the relies on this!!!
* XXX This restriction can and will be fixed by creating a set of flash operation functions that take partition as an additional parameter.
*/
static __attribute__((unused)) void createPartition(flashPartitionType_e type, uint32_t size, flashSector_t *endSector)
{
const flashGeometry_t *flashGeometry = flashGetGeometry();
flashSector_t partitionSectors = (size / flashGeometry->sectorSize);
if (size % flashGeometry->sectorSize > 0) {
partitionSectors++; // needs a portion of a sector.
}
flashSector_t startSector = (*endSector + 1) - partitionSectors; // + 1 for inclusive
flashPartitionSet(type, startSector, *endSector);
*endSector = startSector - 1;
}
static void flashConfigurePartitions(void)
{
const flashGeometry_t *flashGeometry = flashGetGeometry();
if (flashGeometry->totalSize == 0) {
return;
}
flashSector_t startSector = 0;
flashSector_t endSector = flashGeometry->sectors - 1; // 0 based index
const flashPartition_t *badBlockPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT);
if (badBlockPartition) {
endSector = badBlockPartition->startSector - 1;
}
#if defined(FIRMWARE_SIZE)
createPartition(FLASH_PARTITION_TYPE_FIRMWARE, FIRMWARE_SIZE*1024, &endSector);
#endif
#if defined(MSP_FIRMWARE_UPDATE)
createPartition(FLASH_PARTITION_TYPE_FIRMWARE_UPDATE_META, flashGeometry->sectorSize, &endSector);
createPartition(FLASH_PARTITION_TYPE_UPDATE_FIRMWARE, FLASH_SIZE*1024, &endSector);
createPartition(FLASH_PARTITION_TYPE_FULL_BACKUP, FLASH_SIZE*1024, &endSector);
#endif
#if defined(CONFIG_IN_EXTERNAL_FLASH)
createPartition(FLASH_PARTITION_TYPE_CONFIG, EEPROM_SIZE, &endSector);
#endif
#ifdef USE_FLASHFS
flashPartitionSet(FLASH_PARTITION_TYPE_FLASHFS, startSector, endSector);
#endif
}
flashPartition_t *flashPartitionFindByType(uint8_t type)
{
for (int index = 0; index < FLASH_MAX_PARTITIONS; index++) {
flashPartition_t *candidate = &flashPartitionTable.partitions[index];
if (candidate->type == type) {
return candidate;
}
}
return NULL;
}
const flashPartition_t *flashPartitionFindByIndex(uint8_t index)
{
if (index >= flashPartitions) {
return NULL;
}
return &flashPartitionTable.partitions[index];
}
void flashPartitionSet(uint8_t type, uint32_t startSector, uint32_t endSector)
{
flashPartition_t *entry = flashPartitionFindByType(type);
if (!entry) {
if (flashPartitions == FLASH_MAX_PARTITIONS - 1) {
return;
}
entry = &flashPartitionTable.partitions[flashPartitions++];
}
entry->type = type;
entry->startSector = startSector;
entry->endSector = endSector;
}
// Must be in sync with FLASH_PARTITION_TYPE
static const char *flashPartitionNames[] = {
"UNKNOWN ",
"PARTITION",
"FLASHFS ",
"BBMGMT ",
"FIRMWARE ",
"CONFIG ",
"FW UPDT ",
};
const char *flashPartitionGetTypeName(flashPartitionType_e type)
{
if (type < ARRAYLEN(flashPartitionNames)) {
return flashPartitionNames[type];
}
return NULL;
}
bool flashInit(void)
{
memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable));
bool haveFlash = flashDeviceInit();
flashConfigurePartitions();
return haveFlash;
}
int flashPartitionCount(void)
{
return flashPartitions;
}
uint32_t flashPartitionSize(flashPartition_t *partition)
{
const flashGeometry_t * const geometry = flashGetGeometry();
return (partition->endSector - partition->startSector + 1) * geometry->sectorSize;
}
void flashPartitionErase(flashPartition_t *partition)
{
const flashGeometry_t * const geometry = flashGetGeometry();
for (unsigned i = partition->startSector; i <= partition->endSector; i++) {
uint32_t flashAddress = geometry->sectorSize * i;
flashEraseSector(flashAddress);
flashWaitForReady(0);
}
}
#endif // USE_FLASH_CHIP