2023-08-30 16:21:18 +08:00
|
|
|
/*
|
2025-04-23 17:54:31 +08:00
|
|
|
* Copyright (c) 2023-2025, ArtInChip Technology Co., Ltd
|
2023-08-30 16:21:18 +08:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
2024-09-30 17:06:01 +08:00
|
|
|
* Authors: Xiong Hao <hao.xiong@artinchip.com>
|
2023-08-30 16:21:18 +08:00
|
|
|
*/
|
2024-09-30 17:06:01 +08:00
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <aic_core.h>
|
2024-09-30 17:06:01 +08:00
|
|
|
#include <aic_utils.h>
|
|
|
|
|
#include <aic_crc32.h>
|
2023-08-30 16:21:18 +08:00
|
|
|
#include <aicupg.h>
|
|
|
|
|
#include <mtd.h>
|
|
|
|
|
#include <sfud.h>
|
|
|
|
|
#include "upg_internal.h"
|
2024-04-03 16:40:57 +08:00
|
|
|
#include <spienc.h>
|
2025-04-23 17:54:31 +08:00
|
|
|
#include <firmware_security.h>
|
2023-08-30 16:21:18 +08:00
|
|
|
|
2025-07-22 11:15:46 +08:00
|
|
|
#ifdef LPKG_USING_LEVELX
|
|
|
|
|
#include "lx_api.h"
|
|
|
|
|
UINT aic_lx_nor_flash_driver_initialize(LX_NOR_FLASH *nor_flash);
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
#define MAX_DUPLICATED_PART 6
|
|
|
|
|
#define MAX_NOR_NAME 32
|
|
|
|
|
|
2025-07-22 11:15:46 +08:00
|
|
|
#define SECTOR_4K 4 * 1024
|
|
|
|
|
#define SECTOR_32K 32 * 1024
|
|
|
|
|
#define SECTOR_64K 64 * 1024
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
struct aicupg_nor_priv {
|
|
|
|
|
struct mtd_dev *mtd[MAX_DUPLICATED_PART];
|
|
|
|
|
unsigned long start_offset[MAX_DUPLICATED_PART];
|
|
|
|
|
unsigned long erase_offset[MAX_DUPLICATED_PART];
|
2025-07-22 11:15:46 +08:00
|
|
|
#ifdef LPKG_USING_LEVELX
|
|
|
|
|
LX_NOR_FLASH *lx_nor_flash;
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static s32 nor_fwc_get_mtd_partitions(struct fwc_info *fwc,
|
|
|
|
|
struct aicupg_nor_priv *priv)
|
|
|
|
|
{
|
|
|
|
|
char name[MAX_NOR_NAME], *p;
|
|
|
|
|
int cnt = 0, idx = 0;
|
|
|
|
|
|
|
|
|
|
p = fwc->meta.partition;
|
|
|
|
|
while (*p) {
|
|
|
|
|
if (cnt >= MAX_NOR_NAME) {
|
|
|
|
|
pr_err("Partition name is too long.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name[cnt] = *p;
|
|
|
|
|
p++;
|
|
|
|
|
cnt++;
|
|
|
|
|
if (*p == ';' || *p == '\0') {
|
|
|
|
|
name[cnt] = '\0';
|
|
|
|
|
priv->mtd[idx] = mtd_get_device(name);
|
|
|
|
|
if (!priv->mtd[idx]) {
|
|
|
|
|
pr_err("MTD %s part not found.\n", name);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2025-07-22 11:15:46 +08:00
|
|
|
#ifdef LPKG_USING_LEVELX
|
|
|
|
|
if (strstr(fwc->meta.attr, "block")) {
|
|
|
|
|
mtd_erase(priv->mtd[idx], 0, priv->mtd[idx]->size);
|
|
|
|
|
lx_nor_flash_initialize();
|
|
|
|
|
priv->lx_nor_flash = (LX_NOR_FLASH *)malloc(sizeof(LX_NOR_FLASH));
|
|
|
|
|
memset(priv->lx_nor_flash, 0, sizeof(LX_NOR_FLASH));
|
|
|
|
|
priv->lx_nor_flash->mtd_device = priv->mtd[idx];
|
|
|
|
|
if(lx_nor_flash_open(priv->lx_nor_flash, name, aic_lx_nor_flash_driver_initialize))
|
|
|
|
|
pr_err("%s: %d lx_nor_flash_open failed\n", __func__, __LINE__);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
idx++;
|
|
|
|
|
cnt = 0;
|
|
|
|
|
}
|
|
|
|
|
if (*p == ';')
|
|
|
|
|
p++;
|
|
|
|
|
if (*p == '\0')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nor_is_exist()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* storage device prepare,should probe spi norflash
|
|
|
|
|
* - probe spi device
|
|
|
|
|
* - set env for MTD partitions
|
|
|
|
|
* - probe MTD device
|
|
|
|
|
*/
|
|
|
|
|
extern sfud_flash *sfud_probe(u32 spi_bus);
|
|
|
|
|
s32 nor_fwc_prepare(struct fwc_info *fwc, u32 id)
|
|
|
|
|
{
|
|
|
|
|
sfud_flash *flash;
|
|
|
|
|
|
|
|
|
|
flash = sfud_probe(id);
|
|
|
|
|
if (flash == NULL) {
|
|
|
|
|
printf("Failed to probe spinor flash.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-03 16:40:57 +08:00
|
|
|
#ifdef AIC_SPIENC_BYPASS_IN_UPGMODE
|
|
|
|
|
spienc_set_bypass(1);
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* New FirmWare Component start, should prepare to burn FWC to NOR
|
|
|
|
|
* - Get FWC attributes
|
|
|
|
|
* - Parse MTD partitions FWC going to upgrade
|
|
|
|
|
*/
|
|
|
|
|
void nor_fwc_start(struct fwc_info *fwc)
|
|
|
|
|
{
|
|
|
|
|
struct aicupg_nor_priv *priv;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
priv = malloc(sizeof(struct aicupg_nor_priv));
|
|
|
|
|
if (!priv) {
|
|
|
|
|
pr_err("Out of memory, malloc failed.\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
memset(priv, 0, sizeof(struct aicupg_nor_priv));
|
|
|
|
|
fwc->priv = priv;
|
|
|
|
|
|
|
|
|
|
ret = nor_fwc_get_mtd_partitions(fwc, priv);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("Get MTD partitions failed.\n");
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-03 11:16:08 +08:00
|
|
|
#ifdef AIC_USING_SPIENC
|
|
|
|
|
if (strstr(fwc->meta.name, "target.spl"))
|
|
|
|
|
spienc_select_tweak(AIC_SPIENC_HW_TWEAK);
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
fwc->block_size = 2048;
|
|
|
|
|
|
2025-04-23 17:54:31 +08:00
|
|
|
#ifdef AICUPG_FIRMWARE_SECURITY
|
|
|
|
|
firmware_security_init();
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
return;
|
|
|
|
|
err:
|
|
|
|
|
if (priv)
|
|
|
|
|
free(priv);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-22 11:15:46 +08:00
|
|
|
s32 nor_fwc_mtd_erase(struct mtd_dev *mtd, struct aicupg_nor_priv *priv, unsigned long offset, s32 len, int i)
|
|
|
|
|
{
|
|
|
|
|
unsigned long erase_offset;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
erase_offset = priv->erase_offset[i];
|
|
|
|
|
while ((offset + len) > erase_offset) {
|
|
|
|
|
if ((offset + ROUNDUP(len, SECTOR_64K)) <= (mtd->size)) {
|
|
|
|
|
ret = mtd_erase(mtd, erase_offset, ROUNDUP(len, SECTOR_64K));
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
priv->erase_offset[i] = erase_offset + ROUNDUP(len, SECTOR_64K);
|
|
|
|
|
} else if ((offset + ROUNDUP(len, SECTOR_32K)) <= (mtd->size)) {
|
|
|
|
|
ret = mtd_erase(mtd, erase_offset, ROUNDUP(len, SECTOR_32K));
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
priv->erase_offset[i] = erase_offset + ROUNDUP(len, SECTOR_32K);
|
|
|
|
|
} else {
|
|
|
|
|
ret = mtd_erase(mtd, erase_offset, ROUNDUP(len, SECTOR_4K));
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
priv->erase_offset[i] = erase_offset + ROUNDUP(len, SECTOR_4K);
|
|
|
|
|
}
|
|
|
|
|
erase_offset = priv->erase_offset[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-30 16:21:18 +08:00
|
|
|
/*
|
|
|
|
|
* New FirmWare Component write, should write data to NOR
|
|
|
|
|
* - Erase MTD partitions for prepare write
|
|
|
|
|
* - Write data to MTD partions
|
|
|
|
|
*/
|
2025-07-22 11:15:46 +08:00
|
|
|
static s32 nor_fwc_mtd_write(struct fwc_info *fwc, u8 *buf, s32 len)
|
2023-08-30 16:21:18 +08:00
|
|
|
{
|
|
|
|
|
struct aicupg_nor_priv *priv;
|
|
|
|
|
struct mtd_dev *mtd;
|
2025-07-22 11:15:46 +08:00
|
|
|
unsigned long offset;
|
2024-09-30 17:06:01 +08:00
|
|
|
int i, calc_len = 0, ret = 0;
|
2025-04-23 17:54:31 +08:00
|
|
|
u8 __attribute__((unused)) *rdbuf = NULL;
|
2024-09-30 17:06:01 +08:00
|
|
|
|
2025-04-23 17:54:31 +08:00
|
|
|
if ((fwc->meta.size - fwc->trans_size) < len)
|
|
|
|
|
calc_len = fwc->meta.size - fwc->trans_size;
|
|
|
|
|
else
|
|
|
|
|
calc_len = len;
|
|
|
|
|
|
|
|
|
|
fwc->calc_partition_crc = crc32(fwc->calc_partition_crc, buf, calc_len);
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_FIRMWARE_SECURITY
|
|
|
|
|
firmware_security_decrypt(buf, len);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
2024-10-30 16:50:31 +08:00
|
|
|
rdbuf = aicupg_malloc_align(len, CACHE_LINE_SIZE);
|
2024-09-30 17:06:01 +08:00
|
|
|
if (!rdbuf) {
|
|
|
|
|
pr_err("Error: malloc buffer failed.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-04-23 17:54:31 +08:00
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
priv = (struct aicupg_nor_priv *)fwc->priv;
|
|
|
|
|
for (i = 0; i < MAX_DUPLICATED_PART; i++) {
|
|
|
|
|
mtd = priv->mtd[i];
|
|
|
|
|
if (!mtd)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
offset = priv->start_offset[i];
|
|
|
|
|
if ((offset + len) > (mtd->size)) {
|
|
|
|
|
pr_err("Not enough space to write mtd %s\n", mtd->name);
|
2024-09-30 17:06:01 +08:00
|
|
|
goto out;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* erase 1 sector when offset+len more than erased address */
|
2025-07-22 11:15:46 +08:00
|
|
|
ret = nor_fwc_mtd_erase(mtd, priv, offset, len, i);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("MTD erase sector failed!\n");
|
|
|
|
|
goto out;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = mtd_write(mtd, offset, buf, len);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("Write mtd %s error.\n", mtd->name);
|
2024-09-30 17:06:01 +08:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-22 11:15:46 +08:00
|
|
|
|
2025-04-23 17:54:31 +08:00
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
2024-09-30 17:06:01 +08:00
|
|
|
// Read data to calc crc
|
|
|
|
|
ret = mtd_read(mtd, offset, rdbuf, len);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("Read mtd %s error.\n", mtd->name);
|
|
|
|
|
goto out;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
2025-04-23 17:54:31 +08:00
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
priv->start_offset[i] = offset + len;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-30 17:06:01 +08:00
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
2025-04-23 17:54:31 +08:00
|
|
|
if (crc32(0, buf, calc_len) != crc32(0, rdbuf, calc_len)) {
|
2024-09-30 17:06:01 +08:00
|
|
|
pr_err("calc_len:%d\n", calc_len);
|
|
|
|
|
pr_err("crc err at trans len %u\n", fwc->trans_size);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-07-22 11:15:46 +08:00
|
|
|
if (rdbuf)
|
|
|
|
|
aicupg_free_align(rdbuf);
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (rdbuf)
|
|
|
|
|
aicupg_free_align(rdbuf);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef LPKG_USING_LEVELX
|
|
|
|
|
s32 nor_fwc_levelx_write(struct fwc_info *fwc, u8 *buf, s32 len)
|
|
|
|
|
{
|
|
|
|
|
struct aicupg_nor_priv *priv;
|
|
|
|
|
struct mtd_dev *mtd;
|
|
|
|
|
unsigned long offset;
|
|
|
|
|
int i, calc_len = 0, ret = 0;
|
|
|
|
|
u8 __attribute__((unused)) *rdbuf = NULL;
|
|
|
|
|
u32 sec_cnt, sector;
|
|
|
|
|
u8 *temp_ptr = NULL;
|
|
|
|
|
LX_NOR_FLASH *lx_dev;
|
|
|
|
|
|
|
|
|
|
if ((fwc->meta.size - fwc->trans_size) < len)
|
|
|
|
|
calc_len = fwc->meta.size - fwc->trans_size;
|
|
|
|
|
else
|
|
|
|
|
calc_len = len;
|
|
|
|
|
|
|
|
|
|
fwc->calc_partition_crc = crc32(fwc->calc_partition_crc, buf, calc_len);
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_FIRMWARE_SECURITY
|
|
|
|
|
firmware_security_decrypt(buf, len);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
|
|
|
|
rdbuf = aicupg_malloc_align(len, CACHE_LINE_SIZE);
|
|
|
|
|
if (!rdbuf) {
|
|
|
|
|
pr_err("Error: malloc buffer failed.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
priv = (struct aicupg_nor_priv *)fwc->priv;
|
|
|
|
|
lx_dev = priv->lx_nor_flash;
|
|
|
|
|
for (i = 0; i < MAX_DUPLICATED_PART; i++) {
|
|
|
|
|
mtd = priv->mtd[i];
|
|
|
|
|
if (!mtd)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
offset = priv->start_offset[i];
|
|
|
|
|
if ((offset + len) > (mtd->size)) {
|
|
|
|
|
pr_err("Not enough space to write mtd %s\n", mtd->name);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sec_cnt = len / 512;
|
|
|
|
|
sector = offset / 512;
|
|
|
|
|
temp_ptr = buf;
|
|
|
|
|
|
|
|
|
|
while (sec_cnt) {
|
|
|
|
|
ret = lx_nor_flash_sector_write(lx_dev, sector, temp_ptr);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("LeveX write sector %u failed!\n", sector);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sec_cnt--;
|
|
|
|
|
sector++;
|
|
|
|
|
temp_ptr += 512;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
|
|
|
|
// Read data to calc crc
|
|
|
|
|
sec_cnt = len / 512;
|
|
|
|
|
sector = offset / 512;
|
|
|
|
|
temp_ptr = rdbuf;
|
|
|
|
|
while (sec_cnt) {
|
|
|
|
|
ret = lx_nor_flash_sector_read(lx_dev, sector, temp_ptr);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("LeveX read sector %u failed!\n", sector);
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sec_cnt--;
|
|
|
|
|
sector++;
|
|
|
|
|
temp_ptr += 512;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
priv->start_offset[i] = offset + len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef AICUPG_SINGLE_TRANS_BURN_CRC32_VERIFY
|
|
|
|
|
if (crc32(0, buf, calc_len) != crc32(0, rdbuf, calc_len)) {
|
|
|
|
|
pr_err("calc_len:%d\n", calc_len);
|
|
|
|
|
pr_err("crc err at trans len %u\n", fwc->trans_size);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
|
2025-04-23 17:54:31 +08:00
|
|
|
if (rdbuf)
|
|
|
|
|
aicupg_free_align(rdbuf);
|
2023-08-30 16:21:18 +08:00
|
|
|
return len;
|
2024-09-30 17:06:01 +08:00
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (rdbuf)
|
2024-10-30 16:50:31 +08:00
|
|
|
aicupg_free_align(rdbuf);
|
2024-09-30 17:06:01 +08:00
|
|
|
return ret;
|
2023-08-30 16:21:18 +08:00
|
|
|
}
|
2025-07-22 11:15:46 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* New FirmWare Component write, should write data to NOR
|
|
|
|
|
* - Erase MTD partitions for prepare write
|
|
|
|
|
* - Write data to MTD partions
|
|
|
|
|
*/
|
|
|
|
|
s32 nor_fwc_data_write(struct fwc_info *fwc, u8 *buf, s32 len)
|
|
|
|
|
{
|
|
|
|
|
if (aicupg_get_fwc_attr(fwc) & FWC_ATTR_DEV_BLOCK) {
|
|
|
|
|
#ifdef LPKG_USING_LEVELX
|
|
|
|
|
nor_fwc_levelx_write(fwc, buf, len);
|
|
|
|
|
#endif
|
|
|
|
|
} else if (aicupg_get_fwc_attr(fwc) & FWC_ATTR_DEV_MTD) {
|
|
|
|
|
nor_fwc_mtd_write(fwc, buf, len);
|
|
|
|
|
} else {
|
|
|
|
|
/* Do nothing */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (len < 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
fwc->trans_size += len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pr_debug("%s, data len %d, trans len %d\n", __func__, len, fwc->trans_size);
|
|
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
}
|
2023-08-30 16:21:18 +08:00
|
|
|
|
|
|
|
|
s32 nor_fwc_data_read(struct fwc_info *fwc, u8 *buf, s32 len)
|
|
|
|
|
{
|
|
|
|
|
struct aicupg_nor_priv *priv;
|
|
|
|
|
struct mtd_dev *mtd;
|
|
|
|
|
unsigned long offset;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
priv = (struct aicupg_nor_priv *)fwc->priv;
|
|
|
|
|
mtd = priv->mtd[0];
|
|
|
|
|
if (!mtd)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
offset = priv->start_offset[0];
|
|
|
|
|
ret = mtd_read(mtd, offset, buf, len);
|
|
|
|
|
if (ret) {
|
|
|
|
|
pr_err("read mtd %s error.\n", mtd->name);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
priv->start_offset[0] = offset + len;
|
|
|
|
|
|
|
|
|
|
fwc->trans_size += len;
|
|
|
|
|
fwc->calc_partition_crc = fwc->meta.crc;
|
|
|
|
|
pr_debug("%s, data len %d, trans len %d\n", __func__, len, fwc->trans_size);
|
|
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* New FirmWare Component end, should free memory
|
|
|
|
|
* - free the memory what to deposit device information
|
|
|
|
|
*/
|
|
|
|
|
void nor_fwc_data_end(struct fwc_info *fwc)
|
|
|
|
|
{
|
|
|
|
|
struct aicupg_nor_priv *priv;
|
|
|
|
|
|
|
|
|
|
priv = (struct aicupg_nor_priv *)fwc->priv;
|
|
|
|
|
if (!priv)
|
|
|
|
|
return;
|
|
|
|
|
|
2024-09-03 11:16:08 +08:00
|
|
|
#ifdef AIC_USING_SPIENC
|
|
|
|
|
if (strstr(fwc->meta.name, "target.spl"))
|
|
|
|
|
spienc_select_tweak(AIC_SPIENC_USER_TWEAK);
|
|
|
|
|
#endif
|
2023-08-30 16:21:18 +08:00
|
|
|
pr_debug("trans len all %d\n", fwc->trans_size);
|
|
|
|
|
free(priv);
|
|
|
|
|
}
|