/** * Copy backup area application to application entry. * * @param user_app_addr application entry address * @param app_size application size * * @return result */ FlashErrCode flash_copy_app_from_bak(uint32_t user_app_addr, size_t app_size) { size_t cur_size; uint32_t app_cur_addr, bak_cur_addr; FlashErrCode result = FLASH_NO_ERR; /* 32 words size buffer */ uint32_t buff[32]; /* cycle copy data */ for (cur_size = 0; cur_size < app_size; cur_size += sizeof(buff)) { app_cur_addr = user_app_addr + cur_size; bak_cur_addr = get_bak_app_start_addr() + cur_size; flash_read(bak_cur_addr, buff, sizeof(buff)); result = flash_write(app_cur_addr, buff, sizeof(buff)); if (result != FLASH_NO_ERR) { break; } } switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Write data to application entry OK.\n"); break; } case FLASH_WRITE_ERR: { FLASH_INFO("Warning: Write data to application entry fault!\n"); break; } } return result; }
/** * Copy backup area bootloader to bootloader entry. * * @param bl_addr bootloader entry address * @param bl_size bootloader size * * @return result */ FlashErrCode flash_copy_bl_from_bak(uint32_t bl_addr, size_t bl_size) { size_t cur_size; uint32_t bl_cur_addr, bak_cur_addr; FlashErrCode result = FLASH_NO_ERR; /* 32 words buffer */ uint32_t buff[32]; /* cycle copy data by 32bytes buffer */ for (cur_size = 0; cur_size < bl_size; cur_size += sizeof(buff)) { bl_cur_addr = bl_addr + cur_size; bak_cur_addr = get_bak_app_start_addr() + cur_size; flash_read(bak_cur_addr, buff, sizeof(buff)); result = flash_write(bl_cur_addr, buff, sizeof(buff)); if (result != FLASH_NO_ERR) { break; } } switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Write data to bootloader entry OK.\n"); break; } case FLASH_WRITE_ERR: { FLASH_INFO("Warning: Write data to bootloader entry fault!\n"); break; } } return result; }
/** * If the ENV is not exist, create it. * @see flash_write_env * * @param key ENV name * @param value ENV value * * @return result */ static FlashErrCode create_env(const char *key, const char *value) { FlashErrCode result = FLASH_NO_ERR; FLASH_ASSERT(key); FLASH_ASSERT(value); if (*key == NULL) { FLASH_INFO("Flash ENV name must be not empty!\n"); return FLASH_ENV_NAME_ERR; } if (strstr(key, "=")) { FLASH_INFO("Flash ENV name can't contain '='.\n"); return FLASH_ENV_NAME_ERR; } /* find ENV */ if (find_env(key)) { FLASH_INFO("The name of \"%s\" is already exist.\n", key); return FLASH_ENV_NAME_EXIST; } /* write ENV at the end of cache */ result = write_env(key, value); return result; }
/** * Save current using data section address to flash. * * @param cur_data_addr current using data section address * * @return result */ static FlashErrCode save_cur_using_data_addr(uint32_t cur_data_addr) { FlashErrCode result = FLASH_NO_ERR; /* erase ENV system section */ result = flash_erase(get_env_start_addr(), 4); if (result == FLASH_NO_ERR) { /* write current using data section address to flash */ result = flash_write(get_env_start_addr(), &cur_data_addr, 4); if (result == FLASH_WRITE_ERR) { FLASH_INFO("Error: Write system section fault!\n"); FLASH_INFO("Note: The ENV can not be used.\n"); } } else { FLASH_INFO("Error: Erased system section fault!\n"); FLASH_INFO("Note: The ENV can not be used\n"); } return result; }
/** * Erase user old application * * @param user_app_addr application entry address * @param app_size application size * * @return result */ FlashErrCode flash_erase_user_app(uint32_t user_app_addr, size_t app_size) { FlashErrCode result = FLASH_NO_ERR; result = flash_erase(user_app_addr, app_size); switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Erased user application OK.\n"); break; } case FLASH_ERASE_ERR: { FLASH_INFO("Warning: Erase user application fault!\n"); /* will return when erase fault */ return result; } } return result; }
/** * Erase backup area application data. * * @param app_size application size * * @return result */ FlashErrCode flash_erase_bak_app(size_t app_size) { FlashErrCode result = FLASH_NO_ERR; result = flash_erase(get_bak_app_start_addr(), app_size); switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Erased backup area application OK.\n"); break; } case FLASH_ERASE_ERR: { FLASH_INFO("Warning: Erase backup area application fault!\n"); /* will return when erase fault */ return result; } } return result; }
/** * Erase old bootloader * * @param bl_addr bootloader entry address * @param bl_size bootloader size * * @return result */ FlashErrCode flash_erase_bl(uint32_t bl_addr, size_t bl_size) { FlashErrCode result = FLASH_NO_ERR; result = flash_erase(bl_addr, bl_size); switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Erased bootloader OK.\n"); break; } case FLASH_ERASE_ERR: { FLASH_INFO("Warning: Erase bootloader fault!\n"); /* will return when erase fault */ return result; } } return result; }
/** * Delete an ENV in cache. * * @param key ENV name * * @return result */ FlashErrCode flash_del_env(const char *key){ FlashErrCode result = FLASH_NO_ERR; char *del_env_str = NULL; size_t del_env_length, remain_env_length; FLASH_ASSERT(key); if (*key == NULL) { FLASH_INFO("Flash ENV name must be not NULL!\n"); return FLASH_ENV_NAME_ERR; } if (strstr(key, "=")) { FLASH_INFO("Flash ENV name or value can't contain '='.\n"); return FLASH_ENV_NAME_ERR; } /* find ENV */ del_env_str = (char *) find_env(key); if (!del_env_str) { FLASH_INFO("Not find \"%s\" in ENV.\n", key); return FLASH_ENV_NAME_ERR; } del_env_length = strlen(del_env_str); /* '\0' also must be as ENV length */ del_env_length ++; /* the address must multiple of 4 */ if (del_env_length % 4 != 0) { del_env_length = (del_env_length / 4 + 1) * 4; } /* calculate remain ENV length */ remain_env_length = get_env_detail_size() - (((uint32_t) del_env_str + del_env_length) - ((uint32_t) env_cache + ENV_PARAM_PART_BYTE_SIZE)); /* remain ENV move forward */ memcpy(del_env_str, del_env_str + del_env_length, remain_env_length); /* reset ENV end address */ set_env_detail_end_addr(get_env_detail_end_addr() - del_env_length); return result; }
/** * Write data of application to backup area. * * @param data a part of application * @param size data size * @param cur_size current write application size * @param total_size application total size * * @return result */ FlashErrCode flash_write_data_to_bak(uint8_t *data, size_t size, uint32_t *cur_size, size_t total_size) { FlashErrCode result = FLASH_NO_ERR; /* make sure don't write excess data */ if (*cur_size + size > total_size) { size = total_size - *cur_size; } result = flash_write(get_bak_app_start_addr() + *cur_size, (uint32_t *) data, size); switch (result) { case FLASH_NO_ERR: { *cur_size += size; FLASH_INFO("Write data to backup area OK.\n"); break; } case FLASH_WRITE_ERR: { FLASH_INFO("Warning: Write data to backup area fault!\n"); break; } } return result; }
/** * Load flash ENV to ram. */ void flash_load_env(void) { uint32_t *env_cache_bak, env_end_addr, using_data_addr; /* read current using data section address */ flash_read(get_env_start_addr(), &using_data_addr, 4); /* if ENV is not initialize or flash has dirty data, set default for it */ if ((using_data_addr == 0xFFFFFFFF) || (using_data_addr > get_env_start_addr() + flash_get_env_total_size()) || (using_data_addr < get_env_start_addr() + flash_erase_min_size)) { /* initialize current using data section address */ set_cur_using_data_addr(get_env_start_addr() + flash_erase_min_size); /* save current using data section address to flash*/ save_cur_using_data_addr(get_cur_using_data_addr()); /* set default ENV */ flash_env_set_default(); } else { /* set current using data section address */ set_cur_using_data_addr(using_data_addr); /* read ENV detail part end address from flash */ flash_read(get_cur_using_data_addr() + ENV_PARAM_PART_INDEX_END_ADDR * 4, &env_end_addr, 4); /* if ENV end address has error, set default for ENV */ if (env_end_addr > get_env_start_addr() + flash_get_env_total_size()) { flash_env_set_default(); } else { /* set ENV detail part end address */ set_env_detail_end_addr(env_end_addr); env_cache_bak = env_cache + ENV_PARAM_PART_WORD_SIZE; /* read all ENV from flash */ flash_read(get_env_detail_addr(), env_cache_bak, get_env_detail_size()); #ifdef FLASH_ENV_USING_CRC_CHECK /* read ENV CRC code from flash */ flash_read(get_cur_using_data_addr() + ENV_PARAM_PART_INDEX_DATA_CRC * 4, &env_cache[ENV_PARAM_PART_INDEX_DATA_CRC], 4); /* if ENV CRC32 check is fault, set default for it */ if (!env_crc_is_ok()) { FLASH_INFO("Warning: ENV CRC check failed. Set it to default.\n"); flash_env_set_default(); } } #endif } }
/** * Find ENV. * * @param key ENV name * * @return index of ENV in ram cache */ static uint32_t *find_env(const char *key) { uint32_t *env_cache_addr = NULL; char *env_start, *env_end, *env, *env_bak; FLASH_ASSERT(cur_using_data_addr); if (*key == NULL) { FLASH_INFO("Flash ENV name must be not empty!\n"); return NULL; } /* from data section start to data section end */ env_start = (char *) ((char *) env_cache + ENV_PARAM_PART_BYTE_SIZE); env_end = (char *) ((char *) env_cache + ENV_PARAM_PART_BYTE_SIZE + get_env_detail_size()); /* ENV is null */ if (env_start == env_end) { return NULL; } env = env_start; while (env < env_end) { /* storage model is key=value\0 */ env_bak = strstr(env, key); /* the key name length must be equal */ if (env_bak && (env_bak[strlen(key)] == '=')) { env_cache_addr = (uint32_t *) env_bak; break; } else { /* next ENV and word alignment */ if ((strlen(env) + 1) % 4 == 0) { env += strlen(env) + 1; } else { env += ((strlen(env) + 1) / 4 + 1) * 4; } } } return env_cache_addr; }
char * name; unsigned char id[6]; int id_len; int sector_size; int sector_count; int flags; }; struct spi_flash_private_data_t { struct spi_device_t * dev; struct spi_flash_id_t * id; }; static struct spi_flash_id_t spi_flash_ids[] = { /* Atmel */ FLASH_INFO("at25fs010", 0x1f6601, 0, 32 * 1024, 4, SECTOR_4K), FLASH_INFO("at25fs040", 0x1f6604, 0, 64 * 1024, 8, SECTOR_4K), FLASH_INFO("at25df041a", 0x1f4401, 0, 64 * 1024, 8, SECTOR_4K), FLASH_INFO("at25df321a", 0x1f4701, 0, 64 * 1024, 64, SECTOR_4K), FLASH_INFO("at25df641", 0x1f4800, 0, 64 * 1024, 128, SECTOR_4K), FLASH_INFO("at26f004", 0x1f0400, 0, 64 * 1024, 8, SECTOR_4K), FLASH_INFO("at26df081a", 0x1f4501, 0, 64 * 1024, 16, SECTOR_4K), FLASH_INFO("at26df161a", 0x1f4601, 0, 64 * 1024, 32, SECTOR_4K), FLASH_INFO("at26df321", 0x1f4700, 0, 64 * 1024, 64, SECTOR_4K), FLASH_INFO("at45db081d", 0x1f2500, 0, 64 * 1024, 16, SECTOR_4K), /* Winbond */ FLASH_INFO("w25x05", 0xef3010, 0, 64 * 1024, 1, SECTOR_4K), FLASH_INFO("w25x10", 0xef3011, 0, 64 * 1024, 2, SECTOR_4K), FLASH_INFO("w25x20", 0xef3012, 0, 64 * 1024, 4, SECTOR_4K), FLASH_INFO("w25x40", 0xef3013, 0, 64 * 1024, 8, SECTOR_4K),
/** * Save ENV to flash. */ FlashErrCode flash_save_env(void) { FlashErrCode result = FLASH_NO_ERR; uint32_t cur_data_addr_bak = get_cur_using_data_addr(), move_offset_addr; size_t env_detail_size = get_env_detail_size(); /* wear leveling process, automatic move ENV to next available position */ while (get_cur_using_data_addr() + env_detail_size < get_env_start_addr() + flash_get_env_total_size()) { #ifdef FLASH_ENV_USING_CRC_CHECK /* calculate and cache CRC32 code */ env_cache[ENV_PARAM_PART_INDEX_DATA_CRC] = calc_env_crc(); #endif /* erase ENV */ result = flash_erase(get_cur_using_data_addr(), ENV_PARAM_PART_BYTE_SIZE + env_detail_size); switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Erased ENV OK.\n"); break; } case FLASH_ERASE_ERR: { FLASH_INFO("Warning: Erased ENV fault!\n"); FLASH_INFO("Moving ENV to next available position.\n"); /* Calculate move offset address. * Current strategy is optimistic. It will offset the flash erasure minimum size. */ move_offset_addr = flash_erase_min_size; /* calculate and set next available data section address */ set_cur_using_data_addr(get_cur_using_data_addr() + move_offset_addr); /* calculate and set next available ENV detail part end address */ set_env_detail_end_addr(get_env_detail_end_addr() + move_offset_addr); continue; } } /* write ENV to flash */ result = flash_write(get_cur_using_data_addr(), env_cache, ENV_PARAM_PART_BYTE_SIZE + env_detail_size); switch (result) { case FLASH_NO_ERR: { FLASH_INFO("Saved ENV OK.\n"); break; } case FLASH_WRITE_ERR: { FLASH_INFO("Warning: Saved ENV fault!\n"); FLASH_INFO("Moving ENV to next available position.\n"); /* Calculate move offset address. * Current strategy is optimistic. It will offset the flash erasure minimum size. */ move_offset_addr = flash_erase_min_size; /* calculate and set next available data section address */ set_cur_using_data_addr(get_cur_using_data_addr() + move_offset_addr); /* calculate and set next available ENV detail part end address */ set_env_detail_end_addr(get_env_detail_end_addr() + move_offset_addr); continue; } } /* save ENV success */ if (result == FLASH_NO_ERR) { break; } } if (get_cur_using_data_addr() + env_detail_size < get_env_start_addr() + flash_get_env_total_size()) { /* current using data section address has changed, save it */ if (get_cur_using_data_addr() != cur_data_addr_bak) { save_cur_using_data_addr(get_cur_using_data_addr()); } } else { result = FLASH_ENV_FULL; FLASH_INFO("Error: The flash has no available space to save ENV.\n"); /* clear current using data section address on flash */ save_cur_using_data_addr(0xFFFFFFFF); } return result; }