/* * (C) Copyright 2019 * Allwinner Technology Co., Ltd. * * cuizhikui * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include extern __s32 check_sum(__u32 *mem_base, __u32 size); #define STRING(x) #x #define readline(x) cli_readline(x) #define RR_TAB_BLOCK_START (0) #define RR_TAB_PAGE_START (0) #define RR_TAB_PAGE_END (4) #define PAGE_TAB_PAGE_START (4) #define PAGE_TAB_PAGE_END (8) #define DUMP_NAND_ONFO \ "\033[0;36m: [parm1:nand_info]\033[0m\n" #define DUMP_NAND_INFO_HELP \ " For example:want to obtain nand chip info,usage:sunxi_nand_test nand_info\n" #define DUMP_NAND_PAGES \ "\033[0;36m: [parm1:dump_phy_pages] [parm2:chip] [parm3:block] [parm4:start_page] [parm5:end_page] [parm6:pmem] [parm7:printf_flag]\033[0m\n" #define DUMP_NAND_PAGES_HELP \ " For example:want to dump chip 0 block 1 's page 2 to page 5 data to 0x45000000 and don't display in terminal,usage:sunxi_nand_test dump_phy_pages 0 1 2 5 0x45000000 no\n" #define DUMP_BLOCKS \ "\033[0;36m: [parm1:dump_phy_blocks] [parm2:chip num] [parm3:start block num] [parm4:end block num] [parm5:pmem] [parm6:printf_flag]\033[0m\n" #define DUMP_BLOCKS_HELP \ " For example:want to dump chip 0 block 1 to block 5 data to 0x45000000 and don't display in terminal usage:sunxi_nand_test dump_phy_blocks 0 1 5 0x45000000 no\n" #define DUMP_LOGIC_DATA \ "\033[0;36m: [parm1:dump_logic_data] [parm2:start_sector] [parm3:end_sector] [parm4:pmem] [parm5:printf_flag]\033[0m\n" #define DUMP_LOGIC_DATA_HELP \ " For example:want to dump sector 2 to 4 data to 0x45000000 and don't display in terminal,usage:sunxi_nand_test dump_logic_data 2 4 0x45000000 no\n" #define WRITE_NAND_PAGES \ "\033[0;36m: [parm1:write_phy_pages] [parm2:chip] [parm3:block] [parm4:start_page] [parm5:end_page] [parm6:pmem] [parm7:printf_flag]\033[0m\n" #define WRITE_NAND_PAGES_HELP \ " For example:want to write data in 0x45000000 to chip 0 block 1 's page 2 to page 5 and don't display in terminal,usage:sunxi_nand_test write_phy_pages 0 1 2 5 0x45000000 no\n" #define WRITE_BLOCKS \ "\033[0;36m: [parm1:write_phy_blocks] [parm2:chip num] [parm3:start block num] [parm4:end block num] [parm5:pmem] [parm6:printf_flag]\033[0m\n" #define WRITE_BLOCKS_HELP \ " For example:want to write data in 0x45000000 to chip 0 block 1 to block 5 and don't display in terminal usage:sunxi_nand_test write_phy_blocks 0 1 5 0x45000000 no\n" #define ERASE_BLOCKS \ "\033[0;36m: [parm1:erase_phy_blocks] [parm2:chip num] [parm3:start block num] [parm4:end block num] [parm5:printf_flag]\033[0m\n" #define ERASE_BLOCKS_HELP \ " For example:want to erase chip 0 block 1 to block 5 and don't display in terminal usage:sunxi_nand_test erase_phy_blocks 0 1 5 no\n" #define DUMP_HISTORY_DATA \ "\033[0;36m: [parm1:dump_history_data] [parm2:start_sector] [parm3:sector num]\033[0m\n" #define DUMP_HISTORY_DATA_HELP \ " For example:want to dump sector 200' history data,usage:sunxi_nand_test dump_history_data 200 100\n" #define DUMP_READ_RETRY_TABLE \ "\033[0;36m: [parm1:dump_read_retry_table]\033[0m\n" #define DUMP_READ_RETRY_TABLE_HELP \ " For example:want to dump read retry table,usage:sunxi_nand_test dump_read_retry_table\n" #define DUMP_PAGE_TABLE \ "\033[0;36m: [parm1:dump_page_table]\033[0m\n" #define DUMP_PAGE_TABLE_HELP \ " For example:want to dump page table,usage:sunxi_nand_test dump_page_table\n" #define DUMP_BOOT0 "\033[0;36m: [parm1:dump_boot0]\033[0m\n" #define DUMP_BOOT0_HELP \ " For example:want to dump boot0 to 0x45000000 and don't display in terminal,usage:sunxi_nand_test dump_boot0 0x45000000 no\n" #define DUMP_BAD_TABLE \ "\033[0;36m: [parm1:dump_bad_table]\033[0m\n" #define DUMP_BAD_TABLE_HELP \ " For example:want to dump bad block table,usage:sunxi_nand_test dump_bad_table\n" #define DUMP_READ_WRITE_PERFORMANCE \ "\033[0;36m: [parm1:performance]\033[0m\n" #define DUMP_READ_WRITE_PERFORMANCE_HELP \ " For example:want to test performance,usage:sunxi_nand_test performance\n" #define CHECK_READ_WRITE_FUNCTION \ "\033[0;36m: [parm1:check read-write]\033[0m\n" #define CHECK_READ_WRITE_FUNCTION_HELP \ " For example:want to check read-write function is normal,usage:sunxi_nand_test read-write\n" extern int sunxi_flash_get_boot0_size(void); struct sunxi_nand_info { unsigned char id[8]; int chip_cnt; int die_cnt_per_chip; int blks_per_die; unsigned int page_cnt_per_blk; unsigned int sects_per_page; unsigned int multi_program_flag; int super_chip_cnt; unsigned int multi_plane_flag; unsigned int support_v_interleave; unsigned int support_dual_channel; unsigned int blk_cnt_per_super_chip; unsigned int sector_cnt_per_super_page; unsigned int page_cnt_per_super_blk; unsigned int page_offset_for_next_super_blk; unsigned int spare_bytes; unsigned int multi_plane_block_offset; }; static void dumphex(u8 *mem, unsigned int len) { unsigned int i = 0; for (i = 0; i < len; i += 16) { if (i % 16 == 0) printf("%08x:", i); printf("%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", mem[i + 0], mem[i + 1], mem[i + 2], mem[i + 3], mem[i + 4], mem[i + 5], mem[i + 6], mem[i + 7], mem[i + 8], mem[i + 9], mem[i + 10], mem[i + 11], mem[i + 12], mem[i + 13], mem[i + 14], mem[i + 15]); } printf("\n"); } static void dumphex_s_e(u8 *mem, unsigned int start, unsigned int end) { unsigned int i = 0; for (i = start; i < end; i++) { if (i % 16 == 0) printf("%08x:", i); printf("%02x ", mem[i]); if (i % 16 == 15) printf("\n"); } printf("\n"); } static void display_page_table(unsigned int *buf) { boot_file_head_t *bfn = (boot_file_head_t *)buf; unsigned int page_cnt_per_blk = nand_get_chip_block_size(PAGE); int page_cnt = bfn->platform[0]; int copy_cnt = bfn->platform[1]; int i, j; int offset = 0; printf("\033[0;31mpage table:\033[0m\n"); if (copy_cnt == 1) { for (j = 0; j < page_cnt; j++) { /*16=head_size/sizeof(int)=NDFC_PAGE_TAB_HEAD_SIZE(64)/4*/ printf("%4d ", *(buf + j + 16)); } printf("\n"); } else { for (i = 0; i < copy_cnt; i++) { printf("\033[0;34m%d copy in:\033[0m\n", i + 1); for (j = 0; j < page_cnt; j++) { offset = i + j * copy_cnt; /*16=head_size/sizeof(int)=NDFC_PAGE_TAB_HEAD_SIZE(64)/4*/ if (j % 4 == 0) printf("\n"); printf("b@%02dp%04d ", *(buf + offset + 16) / page_cnt_per_blk, *(buf + offset + 16) % page_cnt_per_blk); } printf("\n"); } } } int sunxi_nand_info_dump(void *buffer) { unsigned char id[8] = { 0 }; int chip_cnt = nand_get_chip_cnt(); int die_cnt_per_chip = nand_get_chip_die_cnt(); int blks_per_die = nand_get_chip_die_size(BLOCK); unsigned int page_cnt_per_blk = nand_get_chip_block_size(PAGE); unsigned int sects_per_page = nand_get_chip_page_size(SECTOR); unsigned int multi_program_flag = nand_get_muti_program_flag(); int super_chip_cnt = nand_get_super_chip_cnt(); unsigned int multi_plane_flag = nand_get_twoplane_flag(); unsigned int support_v_interleave = nand_get_support_v_interleave_flag(); unsigned int support_dual_channel = nand_get_support_dual_channel(); unsigned int blk_cnt_per_super_chip = nand_get_super_chip_size(); unsigned int sector_cnt_per_super_page = nand_get_super_chip_page_size(); unsigned int page_cnt_per_super_blk = nand_get_super_chip_block_size(); unsigned int page_offset_for_next_super_blk = nand_get_super_chip_pages_offset_to_block(); unsigned int spare_bytes = nand_get_super_chip_spare_size(); unsigned int multi_plane_block_offset = nand_get_chip_multi_plane_block_offset(); nand_get_chip_id(id, sizeof(id)); struct sunxi_nand_info *nand_info = malloc_cache_aligned(sizeof(struct sunxi_nand_info)); if (nand_info == NULL) { printf("nand_info malloc err\n"); return -1; } nand_get_chip_id(nand_info->id, sizeof(nand_info->id)); nand_info->chip_cnt = nand_get_chip_cnt(); nand_info->die_cnt_per_chip = nand_get_chip_die_cnt(); nand_info->blks_per_die = nand_get_chip_die_size(BLOCK); nand_info->page_cnt_per_blk = nand_get_chip_block_size(PAGE); nand_info->sects_per_page = nand_get_chip_page_size(SECTOR); nand_info->multi_program_flag = nand_get_muti_program_flag(); nand_info->super_chip_cnt = nand_get_super_chip_cnt(); nand_info->multi_plane_flag = nand_get_twoplane_flag(); nand_info->support_v_interleave = nand_get_support_v_interleave_flag(); nand_info->support_dual_channel = nand_get_support_dual_channel(); nand_info->blk_cnt_per_super_chip = nand_get_super_chip_size(); nand_info->sector_cnt_per_super_page = nand_get_super_chip_page_size(); nand_info->page_cnt_per_super_blk = nand_get_super_chip_block_size(); nand_info->page_offset_for_next_super_blk = nand_get_super_chip_pages_offset_to_block(); nand_info->spare_bytes = nand_get_super_chip_spare_size(); nand_info->multi_plane_block_offset = nand_get_chip_multi_plane_block_offset(); if (buffer) { memcpy(buffer, nand_info, sizeof(struct sunxi_nand_info)); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "total chips", ((struct sunxi_nand_info *)buffer)->chip_cnt, 0); printf("\n"); } free(nand_info); nand_info = NULL; printf("\033[0;34m-------------------------\033[0m\033[0;31m nand info\033[0m\033[0;34m-----------------------------\033[0m\n"); printf("\033[0;34m------------------------- physic layer -------------------------\033[0m"); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m %-30s: %x %x %x %x %x %x %x %x \033[0;34m-\033[0m", "id", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "total chips", chip_cnt, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "total dies", die_cnt_per_chip, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "total blocks", blks_per_die, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "pages_per_block", page_cnt_per_blk, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "sectors_per_page", sects_per_page, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%s \033[0;34m%20c-\033[0m", "support_multi_program", multi_program_flag ? " yes" : " no", 0); printf("\n"); printf("\033[0;34m------------------------- logical layer ------------------------\033[0m"); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "super_chip_cnt", super_chip_cnt, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%s \033[0;34m%20c-\033[0m", "support two plane", multi_plane_flag ? " yes" : " no", 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%s \033[0;34m%20c-\033[0m", "support v interleave", support_v_interleave ? " yes" : " no", 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%s \033[0;34m%20c-\033[0m", "support dual channel", support_dual_channel ? " yes" : " no", 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "blk_cnt_per_super_chip", blk_cnt_per_super_chip, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "sector_cnt_per_super_page", sector_cnt_per_super_page, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "page_cnt_per_super_blk", page_cnt_per_super_blk, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "page_offset_for_next_super_blk", page_offset_for_next_super_blk, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "spare_bytes", spare_bytes, 0); printf("\n"); printf("\033[0;34m-\033[0m \033[0;36m%-30s:%5d \033[0;34m%20c-\033[0m", "multi plane block address offset", multi_plane_block_offset, 0); printf("\n"); printf("\033[0;34m- ---------------------------------------------------- -\033[0m\n"); printf("\033[0;34m----------------------------------------------------------------\033[0m\n"); return 0; } static void sunxi_nand_phy_pages_dump(int chip, int block, int start_page, int end_page, void *pmem, unsigned int print_flag, int mem_flag) { int i = 0; int ret = 0; unsigned long len = 0; unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned char *mbuf = malloc_align(page_size, 64); unsigned char spare[16] = {}; if (!mbuf) { printf("malloc buf fail\n"); return; } /*main data*/ for (i = start_page; i < end_page; i++) { memset(mbuf, 0, page_size); ret = nand_physic_read_page(chip, block, i, page_size >> 9, mbuf, NULL); if (ret < 0) { printf("read chip@%d block@%d page@%d main data fail\n", chip, block, i); memset(mbuf, 0, page_size); } memcpy(pmem + len, mbuf, page_size); if (print_flag) dumphex_s_e(mbuf, i * page_size, (i + 1) * page_size); len = len + page_size; } /*spare data*/ for (i = start_page; i < end_page + 1; i++) { memset(spare, 0, 16); ret = nand_physic_read_page(chip, block, i, 0, NULL, spare); if (ret < 0) { printf("read chip@%d block@%d page@%d spare fail\n", chip, block, i); memset(spare, 0, 16); } if (print_flag) { printf("chip@%d block@%d page@%d spare\n", chip, block, i); dumphex(spare, 16); } } if (mem_flag) { printf("\033[0;36mstart pmem = 0x%x \033[0m\n", (unsigned int)((unsigned int *)pmem)); printf("\033[0;36mend pmem = 0x%x \033[0m\n", (unsigned int)(((unsigned char *)pmem) + len)); } } static void sunxi_nand_phy_pages_write(int chip, int block, int start_page, int end_page, void *pmem, unsigned int print_flag, int mem_flag) { int i = 0; int ret = 0; unsigned long len = 0; unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned char *mbuf; /*main data*/ for (i = start_page; i < end_page + 1; i++) { mbuf = pmem + len; ret = nand_physic_write_page(chip, block, i, page_size >> 9, mbuf, NULL); if (ret < 0) { printf("write chip@%d block@%d page@%d main data fail\n", chip, block, i); } } } static void sunxi_nand_phy_blocks_dump(int chip, int start_block, int end_block, void *pmem, unsigned int print_flag) { int b = 0; /*int p = 0;*/ unsigned long len = 0; int page_num = nand_get_chip_block_size(PAGE); // unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned int block_size = nand_get_chip_block_size(BYTE); /* unsigned char *mbuf = malloc_align(page_size, 64); if (!mbuf) { printf("malloc mbuf fail\n"); return; } */ for (b = start_block; b < end_block + 1; b++) { sunxi_nand_phy_pages_dump(chip, b, 0, page_num - 1, pmem + len, print_flag, 0); len = len + block_size; } printf("\033[0;36mstart pmem = 0x%x \033[0m\n", (unsigned int)((unsigned int *)pmem)); printf("\033[0;36mend pmem = 0x%x \033[0m\n", (unsigned int)((unsigned char *)pmem + len + block_size)); return; } static void sunxi_nand_phy_blocks_write(int chip, int start_block, int end_block, void *pmem, unsigned int print_flag) { int b = 0; unsigned long len = 0; int page_num = nand_get_chip_block_size(PAGE); unsigned int block_size = nand_get_chip_block_size(BYTE); for (b = start_block; b < end_block + 1; b++) { sunxi_nand_phy_pages_write(chip, b, 0, page_num - 1, pmem + len, print_flag, 0); len = len + block_size; } return; } void sunxi_nand_phy_page(int start_page, int nbyte, void *pmem) { int blocks = nand_get_chip_die_size(BLOCK); int npages = nbyte / nand_get_chip_page_size(BYTE); int chip = 0; int start_block, st_page; start_block = start_page / nand_get_chip_block_size(PAGE); st_page = start_page % nand_get_chip_block_size(PAGE); if (start_block > blocks) chip = 1; sunxi_nand_phy_pages_dump(chip, start_block, st_page, npages+st_page, pmem, 0, 0); return; } static void sunxi_nand_logic_data_dump(int start_sector, int end_sector, void *pmem, unsigned int print_flag) { int sector_num = end_sector - start_sector + 1; int ret = 0; ret = sunxi_flash_read(start_sector, sector_num, pmem); if (!ret) { printf("read logic data from %d to %d err\n", start_sector, end_sector); } if (print_flag) { printf("start sector@%d end sector@%d logic data:\n", start_sector, end_sector); dumphex(pmem, sector_num << 9); } printf("\033[0;36mstart pmem = 0x%x \033[0m\n", (unsigned int)(unsigned int *)pmem); printf("\033[0;36mend pmem = 0x%x \033[0m\n", (unsigned int)(((unsigned char *)pmem) + ((sector_num + 1) << 9))); return; } static void sunxi_nand_phy_blocks_erase(int chip, int start_block, int end_block, unsigned int print_flag) { int b = 0; int ret = 0; for (b = start_block; b < end_block + 1; b++) { ret = nand_physic_erase_block(chip, b); if (ret < 0) { printf("erase block %d err\n", b); } } return; } void sunxi_nand_logic_history_data_dump(int start_sector, int sector_num, void *pmem, unsigned int print_flag) { //int sector_num = end_sector - start_sector + 1; int ret = 0; ret = nand_uboot_read_history(start_sector, sector_num, pmem); /*ret = sunxi_flash_read(start_sector, sector_num, pmem);*/ if (!ret) { printf("read logic data from %d to %d err\n", start_sector, start_sector + sector_num); } /* *if (print_flag) { * printf("start sector@%d end sector@%d logic data:\n", start_sector, end_sector); * dumphex(pmem, sector_num << 9); *} */ /* *printf("\033[0;36mstart pmem = 0x%x \033[0m\n", (unsigned int)(unsigned int *)pmem); *printf("\033[0;36mend pmem = 0x%x \033[0m\n", * (unsigned int)(((unsigned char *)pmem) + ((sector_num + 1) << 9))); */ return; } static void sunxi_nand_retry_table_dump(void) { unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned char *page_buf = malloc_align(page_size, 64); ; unsigned char spare_data[64] = { 0 }; int ret = 0; int i = 0, p = 0; boot_file_head_t *bfn = (boot_file_head_t *)page_buf; if (!page_buf) { printf("%s malloc buffer fail\n", __func__); return; } memset(page_buf, 0, page_size); for (p = RR_TAB_PAGE_START; p < RR_TAB_PAGE_END; p++) { memset(page_buf, 0, page_size); ret = nand_physic_read_page(0, RR_TAB_BLOCK_START, p, page_size, page_buf, spare_data); if (ret < 0) { printf("read rr fail in chip@%d block@%d page%d\n", 0, RR_TAB_BLOCK_START, p); continue; } if (check_sum((unsigned int *)page_buf, bfn->length)) { printf("page : %d not read retry table\n", p); continue; } printf("============= read retry table ==================\n"); for (i = 0; i < sizeof(bfn->magic); i++) { printf("%c", bfn->magic[i]); } printf("\n"); printf("rr table size: %d\n", bfn->length); printf("check sum: 0x%x\n", bfn->check_sum); printf("page size: %d(sectors)\n", bfn->platform[3]); printf("table:\n"); dumphex(page_buf, bfn->length); memset(page_buf, 0, page_size); goto err; } printf("have no read retry table!\n"); err: free_align(page_buf); return; } static void sunxi_nand_page_table_dump(void *buffer) { unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned int pages_per_block = nand_get_chip_block_size(PAGE); unsigned int uboot_start_block = get_uboot_start_block(); unsigned char *page_buf = malloc_align(page_size, 64); if (!page_buf) { printf("%s malloc buffer fail\n", __func__); return ; } unsigned char spare_data[64] = { 0 }; boot_file_head_t *bfn = (boot_file_head_t *)page_buf; int ret = 0; int b, p; int page_cnt; int copy_cnt; if (page_size < 8192 || pages_per_block < 128) { printf("have no page table"); return ; } for (b = 0; b < uboot_start_block; b++) { for (p = PAGE_TAB_PAGE_START; p < PAGE_TAB_PAGE_END; p++) { memset(page_buf, 0, page_size); ret = nand_physic_read_boot0_page(0, b, p, 0, page_buf, spare_data); if (ret < 0) { printf("read page tab fail in chip@%d, block@%d" " page@%d", 0, b, p); continue; } if (bfn->platform[1] == 1) { if (check_sum((unsigned int *)page_buf, 1024)) { continue; } } else { if (check_sum((unsigned int *)page_buf, bfn->length)) { continue; } } break; } break; } if (b == 7) { printf("page table is bad!\n"); goto err; } page_cnt = bfn->platform[0]; copy_cnt = bfn->platform[1]; printf("========================== page table info ========================\n"); printf("%-23s: %d\n", "one copy pages", page_cnt); printf("%-23s: %d\n", "total copy", copy_cnt); printf("storage size one page: %d\n", bfn->platform[3] * 512); display_page_table((unsigned int *)page_buf); if (buffer != NULL) memcpy(buffer, page_buf, page_size); err: free_align(page_buf); return ; } void sunxi_nand_page_table(void *mem) { sunxi_nand_page_table_dump(mem); } void sunxi_nand_bad_block_table_dump(void) { int chip_cnt = nand_get_chip_cnt(); int die_cnt_per_chip = nand_get_chip_die_cnt(); int blks_per_die = nand_get_chip_die_size(BLOCK); int cnt = 0; int c = 0, b = 0; int ret = 0; int total_blocks = die_cnt_per_chip * blks_per_die; unsigned short r[chip_cnt][total_blocks]; memset(r, 0, sizeof(r)); printf("c(chip) b(block)\n"); for (c = 0; c < chip_cnt; c++) { for (b = 0; b < total_blocks; b++) { printf("c@%db@%04d", c, b); ret = nand_physic_bad_block_check(c, b); if (ret < 0) { printf(" is bad\n"); cnt++; r[c][b] = 1; } else { printf(" is good\n"); } } } printf("scan total %d chip, total %d block (%d bad blocks)\n", chip_cnt, chip_cnt * total_blocks, cnt); printf("bad block:\n"); for (c = 0; c < chip_cnt; c++) { for (b = 0; b < total_blocks; b++) { if (r[c][b] == 1) { printf("chip@%d block@%04d ", c, b); if (b % 4 == 0) printf("\n"); } } } return ; } void sunxi_nand_boot0_dump(void *mem, int start, int print_flag) { int ret = 0; int max_len = 64*1024; //unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned char *buf; int len = 0; len = sunxi_flash_get_boot0_size(); buf = malloc_align(len, 64); if (!buf) { printf("%s malloc buffer fail\n", __func__); return; } /*read complete boot0*/ ret = nand_read_boot0(buf, len); if (ret < 0) { printf("%s %d read boot0 fail\n", __func__, __LINE__); return; } if (mem) { memcpy(mem, buf + start, max_len); } if (print_flag) { printf("boot0:\n"); dumphex(buf, len); } printf("\033[0;36mstart pmem = 0x%x \033[0m\n", (unsigned int)((unsigned int *)mem)); printf("\033[0;36mend pmem = 0x%x \033[0m\n", (unsigned int)(((unsigned char *)mem) + len)); free_align(buf); return; } void sunxi_nand_performance_test(int *read_speed, int *write_speed) { int uboot_next_block = get_uboot_next_block(); int secure_next_block = nand_secure_storage_first_build(uboot_next_block); int physic_reserved_block = get_physic_block_reserved(); unsigned int page_size = nand_get_chip_page_size(BYTE); __maybe_unused unsigned int block_size = nand_get_chip_block_size(BYTE); unsigned int pages_per_block = nand_get_chip_block_size(PAGE); unsigned char *page_buf = malloc_align(page_size, 64); if (!page_buf) { printf("%s malloc buffer fail\n", __func__); return; } int ret = 0; int b, p = 0; int chip = 0; unsigned long long len = 0; ulong time = 0; // int read_speed = 0, write_speed = 0; int r_bad[60]; int i = 0; int j = 0; memset(r_bad, 0, sizeof(int) * 60); memset(page_buf, 0xa5, page_size); printf("tese base on block %d - %d\n", secure_next_block, secure_next_block + physic_reserved_block - 1); printf("erase test start ...\n"); time = get_timer(0); for (b = secure_next_block; b < secure_next_block + physic_reserved_block; b++, i++) { ret = nand_physic_erase_block(chip, b); if (ret < 0) { printf("%s erase block %d fail\n", __func__, b); r_bad[i] = b; continue; } } if (write_speed) { printf("write test start ...\n"); time = get_timer(0); for (b = secure_next_block; b < secure_next_block + physic_reserved_block; b++) { for (j = 0; j < i; j++) { if (r_bad[j] == b) break; } if (j != i) continue; for (p = 0; p < pages_per_block; p++) { ret = nand_physic_write_page(chip, b, p, page_size >> 9, page_buf, NULL); if (ret < 0) { printf("%s write block@%d page@%d fail\n", __func__, b, p); continue; } len += page_size; } } time = get_timer(time); printf("time = %lu ms\n", time); printf("write test end len : %llu\n", len); *write_speed = len * 1000 / time / 1024; printf("total test \033[0;36m%llu \033[0mKB\n", len >> 10); printf("time = %lu ms\n", time); printf("speed = \033[0;31m%d KB/s \033[0;0m\n", *write_speed); } /*memset(page_buf, 0, page_size);*/ len = 0; printf("------------------------------------------\n"); if (read_speed) { printf("read test start ...\n"); time = get_timer(0); for (b = secure_next_block; b < secure_next_block + physic_reserved_block; b++) { for (p = 0; p < pages_per_block; p++) { ret = nand_physic_read_page(chip, b, p, page_size >> 9, page_buf, NULL); if (ret < 0) { printf("%s read block@%d page@%d fail\n", __func__, b, p); continue; } len += page_size; } } time = get_timer(time); printf("read test end\n"); *read_speed = (len * 1000) / time / 1024; printf("total test \033[0;36m%llu \033[0mKB\n", len >> 10); printf("time = %lu ms\n", time); printf("speed = \033[0;31m%d KB/s \033[0;0m\n", *read_speed); } memset(page_buf, 0, page_size); for (b = secure_next_block; b < secure_next_block + physic_reserved_block; b++) { ret = nand_physic_erase_block(chip, b); if (ret < 0) { printf("%s erase block fail\n", __func__); continue; } } if (page_buf) free_align(page_buf); return; } void sunxi_nand_wperf_test(int *write_speed) { sunxi_nand_performance_test(NULL, write_speed); } void sunxi_nand_rperf_test(int *read_speed) { sunxi_nand_performance_test(read_speed, NULL); } static void sunxi_nand_performance(void) { int read_speed, write_speed; sunxi_nand_performance_test(&read_speed, &write_speed); } void sunxi_nand_test_read_write_normal(void) { int uboot_next_block = get_uboot_next_block(); int secure_next_block = nand_secure_storage_first_build(uboot_next_block); int physic_reserved_block = get_physic_block_reserved(); unsigned int page_size = nand_get_chip_page_size(BYTE); unsigned char *page_buf = malloc_align(page_size, 64); unsigned char *r_page_buf = malloc_align(page_size, 64); unsigned int pages_per_block = nand_get_chip_block_size(PAGE); unsigned char spare[8] = {}; unsigned char r_spare[8] = {}; if (!page_buf || !r_page_buf) { printf("%s malloc buffer fail\n", __func__); return; } int ret = 0; int b, p = 0; int chip = 0; /*#define TEST (0x74657374)*/ printf("uboot_next_block:%d\n", uboot_next_block); printf("secure_next_block:%d\n", secure_next_block); printf("physic_next_block:%d\n", physic_reserved_block); memset(page_buf, 0xA5, page_size); memset(r_page_buf, 0, page_size); memset(spare, 0xA5, sizeof(spare)); memset(r_spare, 0, sizeof(spare)); for (b = secure_next_block; b < secure_next_block + 1; b++) { printf("block@%d \n", b); ret = nand_physic_erase_block(chip, b); if (ret < 0) { printf("%s erase block fail\n", __func__); continue; } printf("pages_per_block@%d \n", pages_per_block); for (p = 0; p < pages_per_block; p++) { ret = nand_physic_write_page(chip, b, p, page_size >> 9, page_buf, spare); if (ret < 0) { printf("%s write block@%d page@%d fail\n", __func__, b, p); continue; } ret = nand_physic_read_page(chip, b, p, page_size >> 9, r_page_buf, r_spare); if (ret < 0) { printf("%s read block@%d page@%d fail\n", __func__, b, p); continue; } /*compare main data*/ if (memcmp(page_buf, r_page_buf, page_size)) { printf("block@%d page@%d read & write main content is differrent\n", b, p); printf("write main data:\n"); dumphex(page_buf, page_size); printf("read main data:\n"); dumphex(r_page_buf, page_size); } else { printf("b@%d p@%d read & write main is same\n", b, p); } /*compare spare data*/ if (memcmp(spare, r_spare, sizeof(spare))) { printf("block@%d page@%d read & write spare content is differrent\n", b, p); printf("write spare data:\n"); dumphex(spare, page_size); printf("read spare data:\n"); dumphex(r_spare, page_size); } else { printf("b@%d p@%d read & write spare is same\n", b, p); } } ret = nand_physic_erase_block(chip, b); if (ret < 0) { printf("%s erase block fail\n", __func__); continue; } } if (r_page_buf) free_align(r_page_buf); if (page_buf) free_align(page_buf); return; } void sunxi_nand_boot1_dump_for_efex(void *mem, int len) { extern int nand_get_uboot_total_len(void); int ret = 0; unsigned int page_size = nand_get_chip_page_size(BYTE); int length = nand_get_uboot_total_len(); printf("uboot total lenght@%d\n", length); unsigned char *boot1 = malloc_align(ALIGN(length, page_size), 64); static int received; memset(boot1, 0x00, ALIGN(length, page_size)); ret = nand_read_uboot_data(boot1, length); if (ret != 0) { printf("read uboot fail\n"); goto out; } else { memcpy(mem, boot1 + received, len); received += len; } out: free_align(boot1); return; } int do_sunxi_nand_dump(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { int chip = 0; int block1 = 0; int block2 = 0; int page1 = 0; int page2 = 0; int sector1 = 0; int sector2 = 0; unsigned int print_flag = 0; void *pmem = NULL; ulong time = 0; time = get_timer(0); if (!strcmp(argv[1], "nand_info")) { sunxi_nand_info_dump(NULL); } else if (!strcmp(argv[1], "dump_phy_pages")) { if (argc != 8) return CMD_RET_USAGE; chip = simple_strtoul(argv[2], 0, 0); block1 = simple_strtoul(argv[3], 0, 0); page1 = simple_strtoul(argv[4], 0, 0); page2 = simple_strtoul(argv[5], 0, 0); pmem = (void *)simple_strtoul(argv[6], 0, 16); print_flag = strcmp(argv[7], "no") ? 1 : 0; sunxi_nand_phy_pages_dump(chip, block1, page1, page2, pmem, print_flag, 1); } else if (!strcmp(argv[1], "dump_phy_blocks")) { if (argc != 7) return CMD_RET_USAGE; chip = simple_strtoul(argv[2], 0, 0); block1 = simple_strtoul(argv[3], 0, 0); block2 = simple_strtoul(argv[4], 0, 0); pmem = (void *)simple_strtoul(argv[5], 0, 16); print_flag = strcmp(argv[6], "no") ? 1 : 0; sunxi_nand_phy_blocks_dump(chip, block1, block2, pmem, print_flag); } else if (!strcmp(argv[1], "dump_logic_data")) { if (argc != 6) return CMD_RET_USAGE; sector1 = simple_strtoul(argv[2], 0, 0); sector2 = simple_strtoul(argv[3], 0, 0); pmem = (void *)simple_strtoul(argv[4], 0, 16); print_flag = strcmp(argv[5], "no") ? 1 : 0; sunxi_nand_logic_data_dump(sector1, sector2, pmem, print_flag); } else if (!strcmp(argv[1], "erase_phy_blocks")) { if (argc != 6) return CMD_RET_USAGE; chip = simple_strtoul(argv[2], 0, 0); block1 = simple_strtoul(argv[3], 0, 0); block2 = simple_strtoul(argv[4], 0, 0); print_flag = strcmp(argv[5], "no") ? 1 : 0; sunxi_nand_phy_blocks_erase(chip, block1, block2, print_flag); } else if (!strcmp(argv[1], "write_phy_pages")) { if (argc != 8) return CMD_RET_USAGE; chip = simple_strtoul(argv[2], 0, 0); block1 = simple_strtoul(argv[3], 0, 0); page1 = simple_strtoul(argv[4], 0, 0); page2 = simple_strtoul(argv[5], 0, 0); pmem = (void *)simple_strtoul(argv[6], 0, 16); print_flag = strcmp(argv[7], "no") ? 1 : 0; sunxi_nand_phy_pages_write(chip, block1, page1, page2, pmem, print_flag, 1); } else if (!strcmp(argv[1], "write_phy_blocks")) { if (argc != 7) return CMD_RET_USAGE; chip = simple_strtoul(argv[2], 0, 0); block1 = simple_strtoul(argv[3], 0, 0); block2 = simple_strtoul(argv[4], 0, 0); pmem = (void *)simple_strtoul(argv[5], 0, 16); print_flag = strcmp(argv[6], "no") ? 1 : 0; sunxi_nand_phy_blocks_write(chip, block1, block2, pmem, print_flag); } else if (!strcmp(argv[1], "dump_history_data")) { if (argc != 4) return CMD_RET_USAGE; sector1 = simple_strtoul(argv[2], 0, 0); sector2 = simple_strtoul(argv[3], 0, 0); print_flag = strcmp(argv[5], "no") ? 1 : 0; unsigned int len = (sector2 - sector1 + 1) << 9; pmem = malloc_align(len, 64); sunxi_nand_logic_history_data_dump(sector1, sector2, pmem, print_flag); } else if (!strcmp(argv[1], "dump_read_retry_table")) { if (argc != 2) return CMD_RET_USAGE; sunxi_nand_retry_table_dump(); } else if (!strcmp(argv[1], "dump_page_table")) { if (argc != 2) return CMD_RET_USAGE; sunxi_nand_page_table_dump(NULL); } else if (!strcmp(argv[1], "dump_boot0")) { if (argc != 4) return CMD_RET_USAGE; pmem = (void *)simple_strtoul(argv[2], 0, 16); print_flag = strcmp(argv[3], "no") ? 1 : 0; sunxi_nand_boot0_dump(pmem, 0, print_flag); } else if (!strcmp(argv[1], "dump_bad_table")) { if (argc != 2) return CMD_RET_USAGE; sunxi_nand_bad_block_table_dump(); } else if (!strcmp(argv[1], "performance")) { printf("performance start ..."); sunxi_nand_performance(); } else if (!strcmp(argv[1], "read-write")) { printf("check read-write basic function is noraml?"); sunxi_nand_test_read_write_normal(); } else { return CMD_RET_USAGE; } printf("\n"); time = get_timer(time); printf("sunxi_nand cmd time = %lu ms\n", time); return 0; } U_BOOT_CMD( sunxi_nand_test, CONFIG_SYS_MAXARGS, 1, do_sunxi_nand_dump, "sunxi_nand_test sub systerm", "\n" DUMP_NAND_ONFO DUMP_NAND_INFO_HELP DUMP_NAND_PAGES DUMP_NAND_PAGES_HELP DUMP_BLOCKS DUMP_BLOCKS_HELP DUMP_LOGIC_DATA DUMP_LOGIC_DATA_HELP ERASE_BLOCKS ERASE_BLOCKS_HELP WRITE_NAND_PAGES WRITE_NAND_PAGES_HELP WRITE_BLOCKS WRITE_BLOCKS_HELP DUMP_HISTORY_DATA DUMP_HISTORY_DATA_HELP DUMP_READ_RETRY_TABLE DUMP_READ_RETRY_TABLE_HELP DUMP_PAGE_TABLE DUMP_PAGE_TABLE_HELP DUMP_BAD_TABLE DUMP_BAD_TABLE_HELP DUMP_BOOT0 DUMP_BOOT0_HELP DUMP_READ_WRITE_PERFORMANCE DUMP_READ_WRITE_PERFORMANCE_HELP CHECK_READ_WRITE_FUNCTION CHECK_READ_WRITE_FUNCTION_HELP "\n");