Skip to content

Instantly share code, notes, and snippets.

@nickfox-taterli
Created September 17, 2025 15:12
Show Gist options
  • Select an option

  • Save nickfox-taterli/139f24380dd87c59dd9a2986b1201bfc to your computer and use it in GitHub Desktop.

Select an option

Save nickfox-taterli/139f24380dd87c59dd9a2986b1201bfc to your computer and use it in GitHub Desktop.
fb_spacemit_no_tlv.c
// SPDX-License-Identifier: GPL-2.0+
/* =============================================================================
* FIXUP NOTICE (by TaterLi):
* 本文件为去除 TLV/EEPROM 依赖后的版本(fb_spacemit_no_tlv.c).
* 主要变更:
* 1) 删除 <tlv_eeprom.h> 头文件依赖.
* 2) fastboot_oem config 相关接口改为仅访问 U‑Boot 环境变量,flush=saveenv.
* 3) 清除存储的 eeprom 擦除分支改为直接 FAIL,提示不再支持.
* 4) 在修改处添加了 "FIXUP" 标记与中文注释,方便审阅与回退.
* 注意:若仍需 EEPROM/TLV,请在上层通过 env 注入数据或自行恢复相关代码.
* ============================================================================= */
/*
* Copyright (c) 2023 Spacemit, Inc
*/
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <config.h>
#include <fastboot.h>
#include <malloc.h>
#include <common.h>
#include <fastboot-internal.h>
#include <image-sparse.h>
#include <image.h>
#include <part.h>
#include <mmc.h>
#include <div64.h>
#include <fb_spacemit.h>
#include <mapmem.h>
#include <memalign.h>
#include <u-boot/crc.h>
#include <dm.h>
#include <dm/uclass-internal.h>
#include <cJSON.h>
#include <mtd.h>
#include <spl.h>
#include <linux/io.h>
#include <fb_mtd.h>
#include <nvme.h>
/* FIXUP: 移除TLV EEPROM依赖,删除头文件包含 <tlv_eeprom.h> */
#include <misc.h>
#include <search.h>
#include <env_internal.h>
#define EMMC_MAX_BLK_WRITE 16384
#if CONFIG_IS_ENABLED(SPACEMIT_FLASH)
int _write_gpt_partition(struct flash_dev *fdev)
{
char *gpt_table_str = NULL;
int ret = 0;
u32 boot_mode = get_boot_pin_select();
if (fdev->gptinfo.gpt_table != NULL && strlen(fdev->gptinfo.gpt_table) > 0){
gpt_table_str = malloc(strlen(fdev->gptinfo.gpt_table) + 32);
if (gpt_table_str == NULL){
pr_err("malloc size fail\n");
return -1;
}
sprintf(gpt_table_str, "env set -f partitions '%s'", fdev->gptinfo.gpt_table);
run_command(gpt_table_str, 0);
} else{
pr_info("parse gpt table is NULL, do nothing");
return 0;
}
memset(gpt_table_str, 0, strlen(fdev->gptinfo.gpt_table) + 32);
switch(boot_mode){
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
case BOOT_MODE_EMMC:
case BOOT_MODE_SD:
sprintf(gpt_table_str, "gpt write mmc %x '%s'",
CONFIG_FASTBOOT_FLASH_MMC_DEV, fdev->gptinfo.gpt_table);
if (run_command(gpt_table_str, 0)){
pr_err("write gpt fail");
ret = -1;
goto err;
}
break;
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_SUPPORT_BLOCK_DEV)
case BOOT_MODE_NOR:
case BOOT_MODE_NAND:
char *blk_name;
int blk_index;
if (get_available_blk_dev(&blk_name, &blk_index)){
ret = -1;
goto err;
}
pr_info("write gpt to dev:%s\n", blk_name);
sprintf(gpt_table_str, "gpt write %s %x '%s'",
blk_name, blk_index, fdev->gptinfo.gpt_table);
if (run_command(gpt_table_str, 0)){
pr_err("write gpt fail");
ret = -1;
goto err;
}
break;
#endif
default:
pr_err("no dev to write gpt table, check your env\n");
ret = -1;
goto err;
}
pr_info("parse gpt/mtd table okay");
err:
free(gpt_table_str);
return ret;
}
int _clear_env_part(void *download_buffer, u32 download_bytes,
struct flash_dev *fdev)
{
u32 boot_mode = get_boot_pin_select();
switch(boot_mode){
#ifdef CONFIG_ENV_IS_IN_MMC
case BOOT_MODE_EMMC:
case BOOT_MODE_SD:
/*write to emmc default offset*/
debug("write env to mmc offset:%lx\n", (ulong)FLASH_ENV_OFFSET_MMC);
/*should not write env to env part*/
memset(download_buffer, 0, CONFIG_ENV_SIZE);
fastboot_mmc_flash_offset((u32)FLASH_ENV_OFFSET_MMC, download_buffer, (u32)CONFIG_ENV_SIZE);
break;
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MTD) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MTD)
case BOOT_MODE_NOR:
case BOOT_MODE_NAND:
if (strlen(fdev->mtd_table) > 0){
pr_info("updata mtd env, table:%s\n", fdev->mtd_table);
/* find env partition and write env data to mtd part*/
struct part_info *part;
struct mtd_info *mtd;
int ret;
ret = fb_mtd_lookup("env", &mtd, &part);
if (ret) {
pr_err("invalid mtd device\n");
return -1;
}
ret = _fb_mtd_erase(mtd, CONFIG_ENV_SIZE);
if (ret)
return -1;
}
break;
#endif
default:
break;
}
return 0;
}
int _write_mtd_partition(struct flash_dev *fdev)
{
#ifdef CONFIG_MTD
struct mtd_info *mtd;
char mtd_ids[36] = {"\0"};
char *mtd_parts = NULL;
mtd_parts = malloc(strlen(fdev->mtd_table) + 32);
if (mtd_parts == NULL){
pr_err("malloc size fail\n");
return -1;
}
mtd_probe_devices();
/*
try to find the first mtd device, it there have mutil mtd device such as nand and nor,
it only use the first one.
*/
mtd_for_each_device(mtd) {
if (!mtd_is_partition(mtd))
break;
}
if (mtd == NULL){
pr_err("can not get mtd device");
free(mtd_parts);
return -1;
}
/*to mtd device, it should write mtd table to env.*/
sprintf(mtd_ids, "%s=spi-dev", mtd->name);
sprintf(mtd_parts, "spi-dev:%s", fdev->mtd_table);
env_set("mtdids", mtd_ids);
env_set("mtdparts", mtd_parts);
#endif
pr_info("parse gpt/mtd table okay");
return 0;
}
/**
* @brief transfer the string of size 'K' or 'M' to u32 type.
*
* @param reserve_size , the string of size
* @return int , return the transfer result of KB.
*/
int transfer_string_to_ul(const char *reserve_size)
{
char *ret, *token;
char ch[3] = {"\0"};
char strnum[10] = {"\0"};
u32 get_size = 0;
const char *get_char = reserve_size;
if (get_char == NULL || strlen(get_char) == 0)
return 0;
if (!strncmp("-", get_char, 1)){
return 0;
}
ret = strpbrk(get_char, "KMG");
if (ret == NULL){
pr_debug("can not get char\n");
return 0;
}
strncpy(ch, ret, 1);
if (ch[0] == 'K' || ch[0] == 'M' || ch[0] == 'G'){
pr_debug("reserve_size:%s, reserve_size len:%ld\n", reserve_size, strlen(reserve_size));
strncpy(strnum, reserve_size, strlen(reserve_size));
token = strtok(strnum, ch);
pr_debug("token:%s, ch:%s\n", token, ch);
get_size = simple_strtoul(token, NULL, 0);
}else{
pr_debug("not support size %s, should use K/M/G\n", reserve_size);
return 0;
}
switch(ch[0]){
case 'K':
return get_size;
case 'M':
return get_size * 1024;
case 'G':
return get_size * 1024 * 1024;
}
return 0;
}
/**
* @brief parse the flash_config and save partition info
*
* @param fdev , struct flash_dev
* @return u32 , return 0 if parse config success.
*/
int _parse_flash_config(struct flash_dev *fdev, void *load_flash_addr)
{
u32 part_index = 0;
bool parse_mtd_partition = false;
cJSON *json_root;
int result = 0;
char *combine_str = NULL;
int combine_len = 1;
int combine_size = 0;
int combine_len_extra = 0;
int off = 0;
/*init and would remalloc while size is increasing*/
combine_str = malloc(combine_len);
if (combine_str == NULL)
return -1;
memset(combine_str, '\0', combine_len);
json_root = cJSON_Parse(load_flash_addr);
if (!json_root){
pr_err("can not parse json, check your flash_config.cfg is json format or not\n");
return -1;
}
/*judge if parse mtd or gpt partition*/
cJSON *cj_format = cJSON_GetObjectItem(json_root, "format");
if (cj_format && cj_format->type == cJSON_String){
if (!strncmp("gpt", cj_format->valuestring, 3)){
fdev->gptinfo.fastboot_flash_gpt = true;
combine_len_extra = 20;
}else if(!strncmp("mtd", cj_format->valuestring, 3)){
parse_mtd_partition = true;
combine_len_extra = 6;
}
}
cJSON *cj_parts = cJSON_GetObjectItem(json_root, "partitions");
if (cj_parts && cj_parts->type == cJSON_Array){
for(int i = 0; i < cJSON_GetArraySize(cj_parts); i++){
const char *node_part = NULL;
const char *node_file = NULL;
const char *node_offset = NULL;
const char *node_size = NULL;
fdev->parts_info[part_index].hidden = false;
cJSON *arraypart = cJSON_GetArrayItem(cj_parts, i);
cJSON *cj_name = cJSON_GetObjectItem(arraypart, "name");
if (cj_name && cj_name->type == cJSON_String)
node_part = cj_name->valuestring;
else
node_part = "";
/*bootinfo should be hidden as default in gpt partition*/
if (!parse_mtd_partition){
if (strlen(node_part) > 0 && !strncmp("bootinfo", node_part, 8)){
pr_info("bootinfo would not add as partition\n");
continue;
}
}
cJSON *cj_hidden = cJSON_GetObjectItem(arraypart, "hidden");
if (cj_hidden){
if ((cj_hidden->type == cJSON_String && strcmp("true", cj_hidden->valuestring) == 0)
|| cj_hidden->type == cJSON_True){
printf("!!!! patr name:%s would set to hidden part !!!!\n", node_part);
fdev->parts_info[part_index].hidden = true;
}
}
cJSON *cj_filename = cJSON_GetObjectItem(arraypart, "image");
if (cj_filename && cj_filename->type == cJSON_String)
node_file = cj_filename->valuestring;
else
node_file = "";
cJSON *cj_volume_images = cJSON_GetObjectItem(arraypart, "volume_images");
if (cj_volume_images) {
int volume_count = cJSON_GetArraySize(cj_volume_images);
fdev->parts_info[part_index].volume_images = malloc(volume_count * sizeof(struct flash_volume_image));
fdev->parts_info[part_index].volume_images_count = volume_count;
int volume_index = 0;
cJSON *cj_volume_image = NULL;
cJSON_ArrayForEach(cj_volume_image, cj_volume_images) {
const char *volume_name = cj_volume_image->string;
const char *image_file = cj_volume_image->valuestring;
fdev->parts_info[part_index].volume_images[volume_index].name = strdup(volume_name);
fdev->parts_info[part_index].volume_images[volume_index].file_name = strdup(image_file);
volume_index++;
}
}
cJSON *cj_offset = cJSON_GetObjectItem(arraypart, "offset");
if (cj_offset && cj_offset->type == cJSON_String)
node_offset = cj_offset->valuestring;
else
node_offset = "";
cJSON *cj_size = cJSON_GetObjectItem(arraypart, "size");
if (cj_size && cj_size->type == cJSON_String)
node_size = cj_size->valuestring;
else
node_size = "";
/*make sure that offset would not over than previous size and offset*/
off = transfer_string_to_ul(node_offset);
if (off > 0 && off < combine_size){
pr_err("offset must larger then previous, off:%x, combine_size:%x\n", off, combine_size);
return -5;
}
combine_len += strlen(node_part) + strlen(node_offset) + strlen(node_size) + combine_len_extra;
combine_str = realloc(combine_str, combine_len);
if (combine_str == NULL){
pr_err("realloc combine_str fail\n");
return -1;
}
/*if next part has define offset, use it offset, or it would caculate front part offset and size*/
if (off > 0)
combine_size = off;
/*TODO: support hidden partition for mtd dev*/
if (parse_mtd_partition){
/*parse mtd partition*/
if (strlen(combine_str) == 0)
sprintf(combine_str, "%s%s@%dK(%s)", combine_str, node_size, combine_size, node_part);
else
sprintf(combine_str, "%s,%s@%dK(%s)", combine_str, node_size, combine_size, node_part);
}else if (!fdev->parts_info[part_index].hidden && fdev->gptinfo.fastboot_flash_gpt){
/*parse gpt partition*/
if (strlen(node_offset) == 0)
sprintf(combine_str, "%sname=%s,size=%s;", combine_str, node_part, node_size);
else
sprintf(combine_str, "%sname=%s,start=%s,size=%s;", combine_str, node_part, node_offset, node_size);
}
/*save part offset and size to byte*/
fdev->parts_info[part_index].part_offset = combine_size * 1024;
fdev->parts_info[part_index].part_size = transfer_string_to_ul(node_size) * 1024;
/*save as the next part offset*/
combine_size += transfer_string_to_ul(node_size);
/*after finish recovery, it would free the malloc paramenter at func recovery_show_result*/
fdev->parts_info[part_index].part_name = malloc(strlen(node_part));
if (!fdev->parts_info[part_index].part_name){
pr_err("malloc part_name fail\n");
result = RESULT_FAIL;
goto free_cjson;
}
strcpy(fdev->parts_info[part_index].part_name, node_part);
fdev->parts_info[part_index].size = malloc(strlen(node_size));
if (!fdev->parts_info[part_index].size){
pr_err("malloc size fail\n");
result = RESULT_FAIL;
goto free_cjson;
}
strcpy(fdev->parts_info[part_index].size, node_size);
if (node_file == NULL){
pr_err("not set file name, set to null\n");
fdev->parts_info[part_index].file_name = NULL;
}else{
fdev->parts_info[part_index].file_name = malloc(strlen(node_file) + strlen(FLASH_IMG_FOLDER) + 2);
if (!fdev->parts_info[part_index].file_name){
pr_err("malloc file_name fail\n");
result = RESULT_FAIL;
goto free_cjson;
}
if (strlen(FLASH_IMG_FOLDER) > 0){
strcpy(fdev->parts_info[part_index].file_name, FLASH_IMG_FOLDER);
strcat(fdev->parts_info[part_index].file_name, "/");
strcat(fdev->parts_info[part_index].file_name, node_file);
}else{
strcpy(fdev->parts_info[part_index].file_name, node_file);
}
}
pr_info("Part info: %s, %s\n", fdev->parts_info[part_index].part_name, fdev->parts_info[part_index].file_name ? fdev->parts_info[part_index].file_name : "None");
if (fdev->parts_info[part_index].volume_images_count > 0) {
for (int j = 0; j < fdev->parts_info[part_index].volume_images_count; j++) {
pr_info("Volume name: %s, Image file: %s\n",
fdev->parts_info[part_index].volume_images[j].name,
fdev->parts_info[part_index].volume_images[j].file_name);
}
}
part_index++;
}
}else{
pr_err("do not get partition info, check the input file\n");
return -1;
}
if (parse_mtd_partition){
fdev->mtd_table = realloc(fdev->mtd_table, combine_len);
strcpy(fdev->mtd_table, combine_str);
}
else{
fdev->gptinfo.gpt_table = realloc(fdev->gptinfo.gpt_table, combine_len);
strcpy(fdev->gptinfo.gpt_table, combine_str);
}
free_cjson:
cJSON_free(json_root);
free(combine_str);
return result;
}
/**
* fastboot_oem_flash_gpt() - parse flash_config and write gpt table.
*
* @cmd: Named partition to write image to
* @download_buffer: Pointer to image data
* @download_bytes: Size of image data
* @response: Pointer to fastboot response buffer
*/
void fastboot_oem_flash_gpt(const char *cmd, void *download_buffer, u32 download_bytes,
char *response, struct flash_dev *fdev)
{
int ret = 0;
ret = _parse_flash_config(fdev, (void *)fastboot_buf_addr);
if (ret){
if (ret == -1){
pr_err("parsing config fail\n");
}
if (ret == -5)
fastboot_fail("offset must larger then previous size and offset", response);
return;
}
if (strlen(fdev->gptinfo.gpt_table) > 0 && fdev->gptinfo.fastboot_flash_gpt){
if (_write_gpt_partition(fdev)){
fastboot_fail("write gpt tabel fail", response);
return;
}
}
if (strlen(fdev->mtd_table) > 0){
if (_write_mtd_partition(fdev)){
fastboot_fail("write mtd tabel fail", response);
return;
}
}
/*set partition to env*/
if (_clear_env_part(download_buffer, download_bytes, fdev)){
fastboot_fail("clear env fail", response);
return;
}
/*maybe there doesn't have gpt/mtd partition, should not return fail*/
fastboot_okay("parse gpt/mtd table okay", response);
return;
}
/**
* @brief flash env to reserve partition.
*
* @param cmd env
* @param download_buffer load env.bin to addr
* @param download_bytes env.bin size
* @param response
* @param fdev
*/
void fastboot_oem_flash_env(const char *cmd, void *download_buffer, u32 download_bytes,
char *response, struct flash_dev *fdev)
{
char cmdbuf[64] = {'\0'};
/*load env.bin*/
sprintf(cmdbuf, "env import -c 0x%lx 0x%lx", (ulong)download_buffer, (ulong)CONFIG_ENV_SIZE);
if (run_command(cmdbuf, 0)){
pr_err("can not import env, try to load env.txt\n");
memset(cmdbuf, '\0', 32);
/*load env.txt*/
sprintf(cmdbuf, "env import -t 0x%lx", (ulong)download_buffer);
if (run_command(cmdbuf, 0)){
fastboot_fail("Cannot flash env partition", response);
return;
}
}
if (_clear_env_part(download_buffer, download_bytes, fdev)){
fastboot_fail("clear env fail", response);
return;
}
fastboot_okay("flash env partition okay", response);
return;
}
/**
* fb_mmc_blk_write() - Write/erase MMC in chunks of EMMC_MAX_BLK_WRITE
*
* @block_dev: Pointer to block device
* @start: First block to write/erase
* @blkcnt: Count of blocks
* @buffer: Pointer to data buffer for write or NULL for erase
*/
static __maybe_unused lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
lbaint_t blkcnt, const void *buffer)
{
lbaint_t blk = start;
lbaint_t blks_written;
lbaint_t cur_blkcnt;
lbaint_t blks = 0;
int i;
for (i = 0; i < blkcnt; i += EMMC_MAX_BLK_WRITE) {
cur_blkcnt = min((int)blkcnt - i, EMMC_MAX_BLK_WRITE);
if (buffer) {
if (fastboot_progress_callback)
fastboot_progress_callback("writing");
blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
buffer + (i * block_dev->blksz));
} else {
if (fastboot_progress_callback)
fastboot_progress_callback("erasing");
blks_written = blk_derase(block_dev, blk, cur_blkcnt);
}
blk += blks_written;
blks += blks_written;
}
return blks;
}
int flash_mmc_boot_op(struct blk_desc *dev_desc, void *buffer,
int hwpart, u32 buff_sz, u32 offset)
{
lbaint_t blkcnt;
lbaint_t blks;
lbaint_t blkoff;
unsigned long blksz;
// To operate on EMMC_BOOT1/2 (mmc0boot0/1) we first change the hwpart
if (blk_dselect_hwpart(dev_desc, hwpart)) {
pr_err("Failed to select hwpart\n");
return -1;
}
if (buffer) { /* flash */
pr_info("%s, %p\n", __func__, buffer);
/* determine number of blocks to write */
blksz = dev_desc->blksz;
blkcnt = ((buff_sz + (blksz - 1)) & ~(blksz - 1));
blkcnt = lldiv(blkcnt, blksz);
if (blkcnt > dev_desc->lba) {
pr_err("Image size too large\n");
return -1;
}
if (offset % blksz) {
pr_err("offset must be %lx align\n", blksz);
return -1;
}
debug("Start Flashing Image to EMMC_BOOT%d...\n", hwpart);
blkoff = offset / blksz;
blks = fb_mmc_blk_write(dev_desc, blkoff, blkcnt, buffer);
if (blks != blkcnt) {
pr_err("Failed to write EMMC_BOOT%d\n", hwpart);
return -1;
}
pr_info("........ wrote %lu bytes to EMMC_BOOT%d\n",
blkcnt * blksz, hwpart);
}
return 0;
}
/**
* fastboot_mmc_flash_offset() - Write fsbl image to eMMC
*
* @start_offset: start offset to write.
* @download_buffer: Pointer to image data
* @download_bytes: Size of image data
*/
int fastboot_mmc_flash_offset(u32 start_offset, void *download_buffer,
u32 download_bytes)
{
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
struct blk_desc *dev_desc;
struct disk_partition info = {0};
lbaint_t blkcnt;
u32 offset = start_offset;
lbaint_t blks;
dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc){
return -1;
}
part_get_info(dev_desc, 1, &info);
info.blksz = dev_desc->blksz;
if(info.blksz == 0)
return -1;
if (!download_bytes){
pr_err("it should run command 'fastboot stage fsbl.bin' before run flash fsbl\n");
return -1;
}
info.start = offset / info.blksz;
/* determine number of blocks to write */
blkcnt = ((download_bytes + (info.blksz - 1)) & ~(info.blksz - 1));
blkcnt = lldiv(blkcnt, info.blksz);
blks = fb_mmc_blk_write(dev_desc, info.start, blkcnt, download_buffer);
if (blks != blkcnt) {
pr_err("failed writing to device %d\n", dev_desc->devnum);
return -1;
}
pr_info("........ wrote 0x%lx sector bytes to blk offset 0x%lx\n", blkcnt, info.start);
#endif
return 0;
}
u64 checksum64(u64 *baseaddr, u64 size)
{
u64 sum = 0;
u64 i, cachelines;
u64 dwords, bytes;
u8 *data;
// each cache line has 64bytes
cachelines = size / 64;
bytes = size % 64;
dwords = bytes / 8;
bytes = bytes % 8;
for (i = 0; i < cachelines; i++) {
u64 val1 = *(baseaddr + 0);
u64 val2 = *(baseaddr + 1);
u64 val3 = *(baseaddr + 2);
u64 val4 = *(baseaddr + 3);
u64 val5 = *(baseaddr + 4);
u64 val6 = *(baseaddr + 5);
u64 val7 = *(baseaddr + 6);
u64 val8 = *(baseaddr + 7);
sum += val1;
sum += val2;
sum += val3;
sum += val4;
sum += val5;
sum += val6;
sum += val7;
sum += val8;
baseaddr += 8;
}
/*calculate the rest of dowrd*/
for (i = 0; i < dwords; i++) {
sum += *baseaddr;
baseaddr++;
}
data = (u8*)baseaddr;
/*calculate the rest of byte*/
for (i = 0; i < bytes; i++) {
sum += data[i];
}
return sum;
}
int compare_blk_image_val(struct blk_desc *dev_desc, u64 compare_val, lbaint_t part_start_cnt,
ulong blksz, uint64_t image_size)
{
void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
u32 div_times = (image_size + RECOVERY_LOAD_IMG_SIZE - 1) / RECOVERY_LOAD_IMG_SIZE;
u64 calculate = 0;
uint64_t byte_remain = image_size;
uint64_t download_bytes = 0;
u32 blk_size, n;
unsigned long time_start_flash = get_timer(0);
/*if compare_val is 0, return 0 directly*/
if (!compare_val)
return 0;
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
pr_err("invalid mmc device\n");
return -1;
}
for (int i = 0; i < div_times; i++) {
pr_info("download and flash div %d\n", i);
download_bytes = byte_remain > RECOVERY_LOAD_IMG_SIZE ? RECOVERY_LOAD_IMG_SIZE : byte_remain;
blk_size = (download_bytes + (blksz - 1)) / blksz;
n = blk_dread(dev_desc, part_start_cnt, blk_size, load_addr);
if (n != blk_size) {
pr_err("mmc read blk not equal it should be\n");
return -1;
}
// calculate = crc32_wd(crc, (const uchar *)load_addr, download_bytes, CHUNKSZ_CRC32);
calculate += checksum64(load_addr, download_bytes);
part_start_cnt += blk_size;
byte_remain -= download_bytes;
}
pr_info("get calculate value:%llx, compare calculate:%llx\n", calculate, compare_val);
time_start_flash = get_timer(time_start_flash);
pr_info("compare over, use time:%lu ms\n", time_start_flash);
return (calculate == compare_val) ? 0 : -1;
}
int compare_mtd_image_val(struct mtd_info *mtd, u64 compare_val, uint64_t image_size)
{
void *load_addr = (void *)map_sysmem(RECOVERY_LOAD_IMG_ADDR, 0);
u32 div_times = (image_size + RECOVERY_LOAD_IMG_SIZE - 1) / RECOVERY_LOAD_IMG_SIZE;
u64 calculate = 0;
uint64_t byte_remain = image_size;
uint64_t download_bytes = 0;
u32 hdr_off = 0;
int ret;
debug("mtd size:%llx, image_size:%llx\n", mtd->size, image_size);
unsigned long time_start_flash = get_timer(0);
/*if compare_val is 0, return 0 directly*/
if (!compare_val)
return 0;
for (int i = 0; i < div_times; i++) {
pr_info("\ndownload and flash div %d\n", i);
download_bytes = byte_remain > RECOVERY_LOAD_IMG_SIZE ? RECOVERY_LOAD_IMG_SIZE : byte_remain;
ret = _fb_mtd_read(mtd, load_addr, hdr_off, download_bytes, NULL);
if (ret){
pr_err("cannot read data from mtd dev\n");
return -1;
}
// calculate = crc32_wd(calculate, (const uchar *)load_addr, download_bytes, CHUNKSZ_CRC32);
calculate += checksum64(load_addr, download_bytes);
hdr_off += download_bytes;
byte_remain -= download_bytes;
}
pr_info("get calculate value:%llx, compare calculate:%llx\n", calculate, compare_val);
time_start_flash = get_timer(time_start_flash);
pr_info("compare over, use time:%lu ms\n", time_start_flash);
return (calculate == compare_val) ? 0 : -1;
}
/**
* @brief flash bootinfo to reserve partition.
*
* @param cmd
* @param download_buffer
* @param download_bytes
* @param response
* @param fdev
*/
void fastboot_oem_flash_bootinfo(const char *cmd, void *download_buffer,
u32 download_bytes, char *response, struct flash_dev *fdev)
{
#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) || CONFIG_IS_ENABLED(FASTBOOT_MULTI_FLASH_OPTION_MMC)
debug("%s\n", __func__);
struct blk_desc *dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
pr_err("invalid mmc device\n");
if (response)
fastboot_fail("invalid mmc device", response);
return;
}
/*fill up emmc bootinfo*/
struct boot_parameter_info *boot_info;
boot_info = (struct boot_parameter_info *)download_buffer;
memset(boot_info, 0, sizeof(boot_info));
boot_info->magic_code = BOOT_INFO_EMMC_MAGICCODE;
boot_info->version_number = BOOT_INFO_EMMC_VERSION;
boot_info->page_size = BOOT_INFO_EMMC_PAGESIZE;
boot_info->block_size = BOOT_INFO_EMMC_BLKSIZE;
boot_info->total_size = BOOT_INFO_EMMC_TOTALSIZE;
boot_info->spl0_offset = BOOT_INFO_EMMC_SPL0_OFFSET;
boot_info->spl1_offset = BOOT_INFO_EMMC_SPL1_OFFSET;
boot_info->spl_size_limit = BOOT_INFO_EMMC_LIMIT;
strcpy(boot_info->flash_type, "eMMC");
boot_info->crc32 = crc32_wd(0, (const uchar *)boot_info, 0x40, CHUNKSZ_CRC32);
/*flash bootinfo*/
pr_info("bootinfo:%p, boot_info->crc32:%x, sizeof(boot_info):%lx, download_buffer:%p\n", boot_info, boot_info->crc32, sizeof(boot_info), download_buffer);
if (flash_mmc_boot_op(dev_desc, download_buffer, 1, sizeof(boot_info), 0)){
if (response)
fastboot_fail("flash mmc boot fail", response);
return;
}
if (response)
fastboot_okay(NULL, response);
#endif
return;
}
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_CONFIG_ACCESS)
/* =============================================================================
* FIXUP: 移除了TLV/EEPROM依赖 -- 将 fastboot oem config {read|write|flush}
* 映射到 U‑Boot 环境变量,避免访问 I2C EEPROM/TLV.
* 设计说明:
* - read : 从 env 读取(env_get).
* - write : 写入 env(env_set).保持原有"key:value@dest"参数格式,
* 但忽略 dest(历史兼容),只接受到 env.
* - flush : 将环境保存到非易失介质(等价于 saveenv).在 SPL 阶段仅内存更新.
* 注意事项:
* - value 长度仍按原结构体限制(max_len).
* - 若项目仍需 EEPROM,可在上层通过环境变量注入,不再通过这里访问硬件.
* ============================================================================= */
struct oem_config_info
{
const char *name;
uint32_t id; /* FIXUP: 保留字段,不再使用TLV编号,仅用于兼容 */
uint32_t max_len;
char* (*convert)(char *);
};
static const struct oem_config_info config_info[] = {
/* FIXUP: 下列键名保持与原设计一致,max_len 用于输入校验 */
{ "product_name", 0, 32, NULL },
{ "part#", 0, 32, NULL },
{ "serial#", 0, 32, NULL },
{ "ethaddr", 0, 17, NULL },
{ "ethsize", 0, 6, NULL }, /* ethsize <= 65535 */
{ "manufacture_date", 0, 19, NULL },
{ "device_version", 0, 3, NULL },
{ "manufacturer", 0, 32, NULL }
};
/* 根据 key 查找定义 */
static const struct oem_config_info* get_config_info(const char *key)
{
if (!key) return NULL;
for (int i = 0; i < (int)(sizeof(config_info)/sizeof(config_info[0])); i++) {
if (0 == strcmp(key, config_info[i].name))
return &config_info[i];
}
return NULL;
}
/* 读取配置:直接从环境变量拿 */
static void read_oem_configuration(char *config, char *response)
{
const struct oem_config_info* info = get_config_info(config);
if (!info) {
fastboot_fail("key NOT exist", response);
return;
}
const char *val = env_get(info->name);
if (val && *val) {
fastboot_okay((char*)val, response);
} else {
fastboot_fail("key NOT exist", response);
}
}
/* 写入配置:解析 "key:value@dest";忽略 dest,仅写 env */
static void write_oem_configuration(char *config, char *response)
{
if (!config) { fastboot_fail("bad args", response); return; }
char *p = config;
char *kv = strsep(&p, ":"); /* kv = "key" */
char *rest = p; /* rest = "value@dest" 或 "value" */
if (!kv || !rest) { fastboot_fail("bad format", response); return; }
char *value = rest;
char *dest = strchr(rest, '@');
if (dest) { *dest = '
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment