From 0397775c80958bd889ac9ffeebd163666297a73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=8F=AF=E4=BA=AE?= Date: Fri, 22 Dec 2023 10:19:53 +0800 Subject: [PATCH] v1.0.2 fix fitimage issue --- .../baremetal/bootloader/cmd/nand_boot.c | 7 +- .../baremetal/bootloader/cmd/nor_boot.c | 6 +- .../bootloader/lib/aicupg/nand_fwc.c | 2 +- bsp/artinchip/drv_bare/spinand/spinand_mtd.c | 34 +++++--- bsp/peripheral/spinand/inc/spinand.h | 22 +++-- bsp/peripheral/spinand/spinand.c | 87 ++++++++++++++----- 6 files changed, 112 insertions(+), 46 deletions(-) diff --git a/application/baremetal/bootloader/cmd/nand_boot.c b/application/baremetal/bootloader/cmd/nand_boot.c index e16cb943..f6adc7f9 100644 --- a/application/baremetal/bootloader/cmd/nand_boot.c +++ b/application/baremetal/bootloader/cmd/nand_boot.c @@ -64,12 +64,15 @@ static int do_nand_boot(int argc, char *argv[]) info.dev = (void *)mtd; info.bl_len = mtd->writesize; + info.dev_type = DEVICE_SPINAND; - spl_load_simple_fit(&info, &entry_point); + ret = spl_load_simple_fit(&info, &entry_point); + if (ret < 0) + goto out; boot_app((void *)entry_point); - +out: return ret; } diff --git a/application/baremetal/bootloader/cmd/nor_boot.c b/application/baremetal/bootloader/cmd/nor_boot.c index a8725d46..eac73ac1 100644 --- a/application/baremetal/bootloader/cmd/nor_boot.c +++ b/application/baremetal/bootloader/cmd/nor_boot.c @@ -63,11 +63,15 @@ static int do_nor_boot(int argc, char *argv[]) info.dev = (void *)mtd; info.bl_len = 1; + info.dev_type = DEVICE_SPINOR; - spl_load_simple_fit(&info, &entry_point); + ret = spl_load_simple_fit(&info, &entry_point); + if (ret < 0) + goto out; boot_app((void *)entry_point); +out: return ret; } diff --git a/application/baremetal/bootloader/lib/aicupg/nand_fwc.c b/application/baremetal/bootloader/lib/aicupg/nand_fwc.c index df805f0d..78109a9a 100644 --- a/application/baremetal/bootloader/lib/aicupg/nand_fwc.c +++ b/application/baremetal/bootloader/lib/aicupg/nand_fwc.c @@ -78,7 +78,7 @@ static s32 nand_fwc_get_mtd_partitions(struct fwc_info *fwc, priv->nftl_handler[idx]->nandt->block_start = priv->mtd[idx]->start / priv->mtd[idx]->erasesize; priv->nftl_handler[idx]->nandt->block_end = (priv->mtd[idx]->start + priv->mtd[idx]->size) / priv->mtd[idx]->erasesize; - for (int offset_e = priv->mtd[idx]->start; offset_e < priv->mtd[idx]->start + priv->mtd[idx]->size;) { + for (int offset_e = 0; offset_e < priv->mtd[idx]->size;) { mtd_erase(priv->mtd[idx], offset_e, priv->mtd[idx]->erasesize); offset_e += priv->mtd[idx]->erasesize; } diff --git a/bsp/artinchip/drv_bare/spinand/spinand_mtd.c b/bsp/artinchip/drv_bare/spinand/spinand_mtd.c index c0b2ba03..1bf22aea 100644 --- a/bsp/artinchip/drv_bare/spinand/spinand_mtd.c +++ b/bsp/artinchip/drv_bare/spinand/spinand_mtd.c @@ -53,13 +53,13 @@ static int mtd_spinand_read_oob(struct mtd_dev *mtd, u32 offset, u8 *data, flash = (struct aic_spinand *)mtd->priv; if (offset % flash->info->page_size) { - printf("Offset not aligned with a page (0x%x)\r\n", + pr_err("Offset not aligned with a page (0x%x)\r\n", flash->info->page_size); return -1; } if ((mtd->size - offset) < flash->info->page_size) { - printf("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); + pr_err("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); return -1; } @@ -75,6 +75,7 @@ static int mtd_spinand_erase(struct mtd_dev *mtd, u32 offset, u32 len) u8 err; u32 start, dolen; struct aic_spinand *flash; + u32 flash_size = 0; if (!mtd) return -1; @@ -87,6 +88,14 @@ static int mtd_spinand_erase(struct mtd_dev *mtd, u32 offset, u32 len) if ((mtd->size - offset) < dolen) dolen = mtd->size - offset; + flash_size = flash->info->page_size * flash->info->pages_per_eraseblock * + flash->info->block_per_lun; + if ((start + dolen) > flash_size) { + pr_err("Erase range 0x%x out of flash capacity 0x%x!\n", start + dolen, + flash_size); + return -1; + } + err = spinand_erase(flash, start, dolen); return err; } @@ -107,12 +116,12 @@ static int mtd_spinand_block_isbad(struct mtd_dev *mtd, u32 offset) blocksize = flash->info->page_size * flash->info->pages_per_eraseblock; if (offset % blocksize) { - printf("Offset not aligned with a block (0x%x)\r\n", blocksize); + pr_err("Offset not aligned with a block (0x%x)\r\n", blocksize); return -1; } if ((mtd->size - offset) < blocksize) { - printf("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); + pr_err("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); return -1; } @@ -121,7 +130,7 @@ static int mtd_spinand_block_isbad(struct mtd_dev *mtd, u32 offset) err = spinand_block_isbad(flash, blk); if (err != 0) { - printf("Block %d is bad.\n", blk); + pr_err("Block %d is bad.\n", blk); } return err; } @@ -142,12 +151,12 @@ static int mtd_spinand_block_markbad(struct mtd_dev *mtd, u32 offset) blocksize = flash->info->page_size * flash->info->pages_per_eraseblock; if (offset % blocksize) { - printf("Offset not aligned with a block (0x%x)\r\n", blocksize); + pr_err("Offset not aligned with a block (0x%x)\r\n", blocksize); return -1; } if ((mtd->size - offset) < blocksize) { - printf("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); + pr_err("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); return -1; } @@ -156,7 +165,7 @@ static int mtd_spinand_block_markbad(struct mtd_dev *mtd, u32 offset) err = spinand_block_markbad(flash, blk); if (err != 0) { - printf("Mark badblock %d failed.\n",blk); + pr_err("Mark badblock %d failed.\n", blk); } return err; } @@ -196,13 +205,13 @@ static int mtd_spinand_write_oob(struct mtd_dev *mtd, u32 offset, u8 *data, flash = (struct aic_spinand *)mtd->priv; if (offset % flash->info->page_size) { - printf("Offset not aligned with a page (0x%x)\r\n", + pr_err("Offset not aligned with a page (0x%x)\r\n", flash->info->page_size); return -1; } if ((mtd->size - offset) < flash->info->page_size) { - printf("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); + pr_err("Offset: 0x%x is out of mtd size: 0x%lx.\n", offset, mtd->size); return -1; } @@ -260,7 +269,8 @@ static char *aic_spinand_get_partition_string(struct mtd_dev *mtd) parts = strdup(parts); #else void *res_addr = NULL; - res_addr = aic_get_boot_resource_from_nand(mtd, mtd->writesize, nand_read_data); + res_addr = + aic_get_boot_resource_from_nand(mtd, mtd->writesize, nand_read_data); parts = private_get_partition_string(res_addr); if (parts == NULL) parts = IMAGE_CFG_JSON_PARTS_MTD; @@ -303,7 +313,7 @@ struct aic_spinand *spinand_probe(u32 spi_bus) err = spinand_flash_init(flash); if (err < 0) { - printf("Failed to probe spinand flash.\n"); + pr_err("Failed to probe spinand flash.\n"); return NULL; } diff --git a/bsp/peripheral/spinand/inc/spinand.h b/bsp/peripheral/spinand/inc/spinand.h index c49c3091..9e67a3c8 100644 --- a/bsp/peripheral/spinand/inc/spinand.h +++ b/bsp/peripheral/spinand/inc/spinand.h @@ -21,7 +21,7 @@ #undef pr_debug #ifdef AIC_SPINAND_DRV_DEBUG -#define pr_debug pr_info +#define pr_debug pr_info #else #define pr_debug(fmt, ...) #endif @@ -34,6 +34,8 @@ struct nand_bbt { u8 *cache; }; +struct aic_spinand; + /* SPI NAND flash information */ struct aic_spinand_info { u32 devid; @@ -44,6 +46,7 @@ struct aic_spinand_info { u8 is_die_select; const char *sz_description; struct spi_nand_cmd_cfg *cmd; + int (*get_status)(struct aic_spinand *flash, u8 status); }; typedef struct aic_spinand_info *aic_spinand_info_t; @@ -175,14 +178,15 @@ struct spi_nand_cmd_cfg { #define CFG_QUAD_ENABLE BIT(0) /* status register */ -#define REG_STATUS 0xc0 -#define STATUS_BUSY BIT(0) -#define STATUS_ERASE_FAILED BIT(2) -#define STATUS_PROG_FAILED BIT(3) -#define STATUS_ECC_MASK GENMASK(5, 4) -#define STATUS_ECC_NO_BITFLIPS (0 << 4) -#define STATUS_ECC_HAS_BITFLIPS (1 << 4) -#define STATUS_ECC_UNCOR_ERROR (2 << 4) +#define REG_STATUS 0xc0 +#define STATUS_BUSY BIT(0) +#define STATUS_ERASE_FAILED BIT(2) +#define STATUS_PROG_FAILED BIT(3) + +#define STATUS_ECC_MASK GENMASK(5, 4) +#define STATUS_ECC_NO_BITFLIPS (0 << 4) +#define STATUS_ECC_HAS_1_4_BITFLIPS (1 << 4) +#define STATUS_ECC_UNCOR_ERROR (2 << 4) #ifdef SPI_NAND_WINBOND extern const struct spinand_manufacturer winbond_spinand_manufacturer; diff --git a/bsp/peripheral/spinand/spinand.c b/bsp/peripheral/spinand/spinand.c index 34b4b265..1ca9d968 100644 --- a/bsp/peripheral/spinand/spinand.c +++ b/bsp/peripheral/spinand/spinand.c @@ -138,6 +138,27 @@ int spinand_read_cfg(struct aic_spinand *flash, u8 *cfg) return spinand_read_reg_op(flash, REG_CFG, cfg); } +int spinand_check_ecc_status(struct aic_spinand *flash, u8 status) +{ + if (flash->info->get_status) { + return flash->info->get_status(flash, status); + } + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + case STATUS_ECC_HAS_1_4_BITFLIPS: + return 4; + case STATUS_ECC_UNCOR_ERROR: + return -SPINAND_ERR_ECC; + + default: + break; + } + + return -SPINAND_ERR; +} + int spinand_isbusy(struct aic_spinand *flash, u8 *status) { u8 SR = 0xFF; @@ -495,11 +516,13 @@ int spinand_read_page(struct aic_spinand *flash, u32 page, u8 *data, goto exit_spinand_read_page; } - status = (status & 0x30) >> 4; - if ((status > 0x01)) { - result = -SPINAND_ERR_ECC; + result = spinand_check_ecc_status(flash, status); + if (result < 0) { pr_err("Error ECC status error[0x%x].\n", status); goto exit_spinand_read_page; + } else if (result > 0) { + pr_debug("with %d bit/page ECC corrections, status : [0x%x].\n", result, + status); } if (data && data_len) { @@ -658,11 +681,14 @@ int spinand_continuous_read(struct aic_spinand *flash, u32 page, u8 *data, goto exit_spinand_continuous_read; } - status = (status & 0x30) >> 4; - if ((status > 0x01)) { + result = spinand_check_ecc_status(flash, status); + if (result < 0) { result = -SPINAND_ERR_ECC; pr_err("Error ECC status error[0x%x].\n", status); goto exit_spinand_continuous_read; + } else if (result > 0) { + pr_debug("with %d bit/page ECC corrections, status : [0x%x].\n", result, + status); } result = spinand_read_from_cache_cont_op(flash, data, size); @@ -760,11 +786,13 @@ int spinand_write_page(struct aic_spinand *flash, u32 page, const u8 *data, goto exit_spinand_write_page; } - status = (status & 0x30) >> 4; - if ((status > 0x01)) { - result = -SPINAND_ERR_ECC; + result = spinand_check_ecc_status(flash, status); + if (result < 0) { pr_err("Error ECC status error[0x%x].\n", status); goto exit_spinand_write_page; + } else if (result > 0) { + pr_debug("with %d bit/page ECC corrections, status : [0x%x].\n", result, + status); } result = SPINAND_SUCCESS; @@ -796,27 +824,25 @@ int spinand_block_markbad(struct aic_spinand *flash, u16 blk) return spinand_write_page(flash, page, NULL, 0, &badblockmarker, 1); } +#define READ_DATE_OFFSET_ALIGN 1 +#define READ_DATE_OFFSET_UNALIGN 2 + int spinand_read(struct aic_spinand *flash, u8 *addr, u32 offset, u32 size) { int err = 0; u32 page, cplen; u32 off = offset; - u8 *buf = NULL, *p, copy_flag; + u8 *buf = NULL, *p, copy_flag = 0; u32 remaining = size; u16 blk; u32 blk_size; + u32 off_in_page = 0; if (!flash) { pr_err("flash is NULL\r\n"); return -SPINAND_ERR; } - if (offset % flash->info->page_size) { - pr_err("Offset not aligned with a page (0x%x)\r\n", - flash->info->page_size); - return -SPINAND_ERR; - } - buf = malloc(flash->info->page_size + flash->info->oob_size); if (!buf) { pr_err("Failed to malloc spinand buf.\n"); @@ -835,12 +861,19 @@ int spinand_read(struct aic_spinand *flash, u8 *addr, u32 offset, u32 size) } while (remaining > 0) { - if (remaining >= flash->info->page_size) { - p = addr; - copy_flag = 0; + if (off % flash->info->page_size == 0) { + if (remaining >= flash->info->page_size) { + p = addr; + copy_flag = 0; + } else { + p = buf; + copy_flag = READ_DATE_OFFSET_UNALIGN; + memset(buf, 0xFF, flash->info->page_size); + } } else { p = buf; - copy_flag = 1; + copy_flag = READ_DATE_OFFSET_ALIGN; + memset(buf, 0xFF, flash->info->page_size); } page = off / flash->info->page_size; @@ -850,10 +883,22 @@ int spinand_read(struct aic_spinand *flash, u8 *addr, u32 offset, u32 size) goto exit_spinand_read; cplen = flash->info->page_size; - if (remaining < cplen) + + if (copy_flag == READ_DATE_OFFSET_ALIGN) { + /*Misaligned offset with page address*/ + off_in_page = off % flash->info->page_size; + if (remaining <= flash->info->page_size - off_in_page) { + cplen = remaining; + } else { + cplen = flash->info->page_size - off_in_page; + } + memcpy(addr, buf + off_in_page, cplen); + } else if (copy_flag == READ_DATE_OFFSET_UNALIGN) { + /*Align offset with page address*/ cplen = remaining; - if (copy_flag) memcpy(addr, buf, cplen); + } + remaining -= cplen; off += cplen; addr += cplen;