409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			409 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /****************************************************************************
 | ||
|  | 
 | ||
|  | Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED. | ||
|  | 
 | ||
|  | This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT | ||
|  | be copied by any method or incorporated into another program without | ||
|  | the express written consent of Aerospace C.Power. This Information or any portion | ||
|  | thereof remains the property of Aerospace C.Power. The Information contained herein | ||
|  | is believed to be accurate and Aerospace C.Power assumes no responsibility or | ||
|  | liability for its use in any way and conveys no license or title under | ||
|  | any patent or copyright and makes no representation or warranty that this | ||
|  | Information is free from patent or copyright infringement. | ||
|  | 
 | ||
|  | ****************************************************************************/ | ||
|  | 
 | ||
|  | #include "iot_io_api.h"
 | ||
|  | #include "iot_errno_api.h"
 | ||
|  | #include "iot_utils_api.h"
 | ||
|  | 
 | ||
|  | #include "spi_flash.h"
 | ||
|  | #include "iot_spi_api.h"
 | ||
|  | 
 | ||
|  | 
 | ||
|  | /*************************  DEBUG START  ************************/ | ||
|  | #define SPI_FLASH_DEBUG_TEST     0
 | ||
|  | /*************************  DEBUG END  ************************/ | ||
|  | 
 | ||
|  | #if SPI_FLASH_DEBUG_TEST
 | ||
|  | 
 | ||
|  | static char spi_flash_dump_buf[1024 + 16]; | ||
|  | 
 | ||
|  | void spi_flash_dump_bin(void * buf, uint32_t len) | ||
|  | { | ||
|  |     char *p = buf, *q = spi_flash_dump_buf; | ||
|  |     uint32_t i, buf_len; | ||
|  | 
 | ||
|  |     buf_len = iot_sprintf(q, "DUMP(%03d):", len); | ||
|  | 
 | ||
|  |     for(i = 0; (i < len) && (buf_len < 1024); i++, p++) { | ||
|  |         buf_len += iot_sprintf(q + buf_len, " %02x", ((int)*p) & 0xFF); | ||
|  |     } | ||
|  | 
 | ||
|  |     iot_cus_printf("\n[spi_DRV@%04d]:%s", __LINE__, spi_flash_dump_buf); | ||
|  | 
 | ||
|  |     return; | ||
|  | } | ||
|  | 
 | ||
|  | void iot_cus_print_config(bool_t enable); | ||
|  | void iot_print_config(bool_t enable); | ||
|  | uint8_t test_buf[1024]; | ||
|  | uint32_t cycle_count = 0; | ||
|  | char w_buf[SPI_FLASH_PAGE_SIZE]; | ||
|  | char r_buf[SPI_FLASH_PAGE_SIZE]; | ||
|  | 
 | ||
|  | char test_r_buf[SPI_FLASH_SECTOR_SIZE]; | ||
|  | char test_w_buf[SPI_FLASH_SECTOR_SIZE]; | ||
|  | char test_e_buf[SPI_FLASH_SECTOR_SIZE]; | ||
|  | 
 | ||
|  | #define btm_rand_pattern(buf, buf_len, seed) \
 | ||
|  |     do { \ | ||
|  |             int r_pttn; \ | ||
|  |             r_pttn = ((seed >> 24) & 0xFF) ^ \ | ||
|  |                 ((seed >> 16) & 0xFF) ^ ((seed >> 8) & 0xFF); \ | ||
|  |             for(int i = 0; i < buf_len; i++) { \ | ||
|  |                 buf[i] = 0x5a ^ i ^ r_pttn; \ | ||
|  |             } \ | ||
|  |     } while (0) | ||
|  | 
 | ||
|  | /* Test pattern map from PUYA. */ | ||
|  | #define btm_fix_pattern(buf, buf_len, pattern) \
 | ||
|  |     do { \ | ||
|  |             int *pnt = (int *)buf, *pend = (int *)(buf + buf_len); \ | ||
|  |             while (pnt < pend) { \ | ||
|  |                 *pnt = pattern; \ | ||
|  |                 pnt += 2; \ | ||
|  |             } \ | ||
|  |             pnt = (int *)(buf + sizeof(*pnt)); \ | ||
|  |             while (pnt < pend) { \ | ||
|  |                 *pnt = ~pattern; \ | ||
|  |                 pnt += 2; \ | ||
|  |             } \ | ||
|  |     } while (0) | ||
|  | 
 | ||
|  | uint32_t iot_bootram_get_running_time(void) | ||
|  | { | ||
|  |     return gp_timer_get_current_val(0); | ||
|  | } | ||
|  | 
 | ||
|  | static int btm_exe_tool_u32_data_cmp(void *d1, void *d2, int len_u32, | ||
|  |     int *dif_idx) | ||
|  | { | ||
|  |     uint32_t *p1 = d1, *p2 = d2, *p_end; | ||
|  |     int ret = 0; | ||
|  | 
 | ||
|  |     if ((NULL == p1 || NULL == p2) | ||
|  |         || (((int)p1 & 0x3) || ((int)p2 & 0x3))) { | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     p_end = p1 + len_u32; | ||
|  | 
 | ||
|  |     while(p1 < p_end) { | ||
|  |         if (*p1 != *p2) { | ||
|  |             ret = (*p1 < *p2) ? (-1) : (1); | ||
|  |             break; | ||
|  |         } | ||
|  |         p1++; | ||
|  |         p2++; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (p1 < p_end) { | ||
|  |         *dif_idx = ((int)p1 - (int)d1) / sizeof(*p1); | ||
|  |     } else { | ||
|  |         *dif_idx = 0; | ||
|  |     } | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | static int btm_executor_spi_flash_test_sector_rw_scan(uint32_t id, int offset, | ||
|  |     int *err_offset, int *rd_data, int *exp_data, int auto_pattern, int pattern) | ||
|  | { | ||
|  |     int page_s, page_e, page, i, cur_ptn; | ||
|  | 
 | ||
|  |     os_mem_set(w_buf, 0xFF, SPI_FLASH_PAGE_SIZE); | ||
|  | 
 | ||
|  |     page_s = offset & (~(SPI_FLASH_SECTOR_SIZE - 1)); | ||
|  |     page_e = page_s + SPI_FLASH_SECTOR_SIZE; | ||
|  | 
 | ||
|  |     /* Erase sector */ | ||
|  |     spi_flash_raw_erase_sector(id, page_s, SPI_FLASH_SECTOR_SIZE); | ||
|  |     os_delay(1); | ||
|  | 
 | ||
|  |     /* Check erase. */ | ||
|  |     for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) { | ||
|  |         if (ERR_OK != spi_flash_raw_read(id, page, (uint8_t*)r_buf, | ||
|  |             SPI_FLASH_PAGE_SIZE)) { | ||
|  |             iot_cus_printf("[%s][err] read failed!\n", __FUNCTION__); | ||
|  |             goto err_out; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (btm_exe_tool_u32_data_cmp(w_buf, r_buf, | ||
|  |             SPI_FLASH_PAGE_SIZE / sizeof(uint32_t), &i)) { | ||
|  |             iot_cus_printf("\r\n[%d] btm_exe_tool_u32_data_cmp failed\n", __LINE__); | ||
|  |             goto err_out; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     os_delay(1); | ||
|  | 
 | ||
|  |     cur_ptn = pattern; | ||
|  |     /* Write pattern for every page */ | ||
|  |     for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) { | ||
|  |         if (auto_pattern) { | ||
|  |             btm_rand_pattern(w_buf, SPI_FLASH_PAGE_SIZE, page); | ||
|  |         } else { | ||
|  |             btm_fix_pattern(w_buf, SPI_FLASH_PAGE_SIZE, cur_ptn); | ||
|  |             cur_ptn = ~cur_ptn; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (ERR_OK != spi_flash_raw_write_page(id, page, (uint8_t*)w_buf, | ||
|  |             sizeof(w_buf))) { | ||
|  |             iot_cus_printf("[%s][err] write failed!\n", __FUNCTION__); | ||
|  |             goto err_out; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     os_delay(1); | ||
|  | 
 | ||
|  |     cur_ptn = pattern; | ||
|  |     /* Verify data for every page. */ | ||
|  |     for (page = page_s; page < page_e; page += SPI_FLASH_PAGE_SIZE) { | ||
|  |         if (auto_pattern) { | ||
|  |             btm_rand_pattern(w_buf, SPI_FLASH_PAGE_SIZE, page); | ||
|  |         } else { | ||
|  |             btm_fix_pattern(w_buf, SPI_FLASH_PAGE_SIZE, cur_ptn); | ||
|  |             cur_ptn = ~cur_ptn; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (ERR_OK != spi_flash_raw_read(id, page, (uint8_t*)r_buf, | ||
|  |             SPI_FLASH_PAGE_SIZE)) { | ||
|  |             iot_cus_printf("[%s][err] read failed!\n", __FUNCTION__); | ||
|  |             goto err_out; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (btm_exe_tool_u32_data_cmp(w_buf, r_buf, | ||
|  |             SPI_FLASH_PAGE_SIZE / sizeof(uint32_t), &i)) { | ||
|  |             iot_cus_printf("\r\n[%d] btm_exe_tool_u32_data_cmp failed\n", __LINE__); | ||
|  |             goto err_out; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     os_delay(1); | ||
|  | 
 | ||
|  |     iot_cus_printf("[%s][info] cycle %dth test 0x%x ok!\n", __FUNCTION__, | ||
|  |         cycle_count, page_s); | ||
|  | 
 | ||
|  |     return 0; | ||
|  | 
 | ||
|  | err_out: | ||
|  | 
 | ||
|  |     *err_offset = page + i * sizeof(uint32_t); | ||
|  |     *rd_data = *(int *)((int *)r_buf + i); | ||
|  |     *exp_data = *(int *)((int *)w_buf + i); | ||
|  | 
 | ||
|  |     return -1; | ||
|  | } | ||
|  | 
 | ||
|  | uint8_t spi_falsh_test_operate_sector(uint32_t id) | ||
|  | { | ||
|  |     uint32_t time1, time2; | ||
|  |     uint32_t cycle_count = 0; | ||
|  | 
 | ||
|  |     os_mem_set(test_e_buf, 0xff, SPI_FLASH_SECTOR_SIZE); | ||
|  | 
 | ||
|  |     iot_cus_printf("spi_falsh_test_ten_sector  ...\n"); | ||
|  | 
 | ||
|  |     while(1) { | ||
|  |         for (int i = 0; i < SPI_FLASH_SECTOR_SIZE;) { | ||
|  |             if (cycle_count % 2) { | ||
|  |                 test_w_buf[i] = 0xaa; | ||
|  |                 test_w_buf[i+1] = 0x55; | ||
|  |             } else { | ||
|  |                 test_w_buf[i] = 0x55; | ||
|  |                 test_w_buf[i+1] = 0xaa; | ||
|  |             } | ||
|  |             i += 2; | ||
|  |         } | ||
|  | 
 | ||
|  |         time1 = gp_timer_get_current_val(0); | ||
|  |         for (int i = 0; i < 10; i++) { | ||
|  |             if (ERR_OK != spi_flash_raw_erase_sector(id, i * SPI_FLASH_SECTOR_SIZE, | ||
|  |                 SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                 iot_printf("\n[spi_DRV@%04d]:sec#0x%x erase failed!", | ||
|  |                     __LINE__, i * SPI_FLASH_SECTOR_SIZE); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         while(ERR_OK != spi_flash_raw_write_start(id)); | ||
|  |         time2 = gp_timer_get_current_val(0); | ||
|  |         if (time1 > time2) { | ||
|  |             time1 = (((uint32_t)(-1)) - time1 + time2); | ||
|  |         } else { | ||
|  |             time1 = (time2 - time1); | ||
|  |         } | ||
|  | 
 | ||
|  |         for (int i = 0; i < 10; i++) { | ||
|  |             if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) { | ||
|  |                 if ( -1 == custom_ext_dev_read(id, test_r_buf, SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                     iot_cus_printf("[test][err] test cycle_count[%d] - read [%dth] sec failed!!!\n", | ||
|  |                         cycle_count, i+1); | ||
|  |                 } | ||
|  |             } else { | ||
|  |                     iot_cus_printf("[test][err] seek failed!!!\n"); | ||
|  |             } | ||
|  |             if (0 != os_mem_cmp(test_e_buf, test_r_buf, SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                 iot_cus_printf("[test][err] wirte is not match.!!!\n"); | ||
|  |             } | ||
|  |         } | ||
|  |         iot_cus_printf("test erase passed. Takes %u ns.\n", time1); | ||
|  | 
 | ||
|  |         time1 = gp_timer_get_current_val(0); | ||
|  |         for (int i = 0; i < 10; i++) { | ||
|  |             if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) { | ||
|  |                 if ( -1 == custom_ext_dev_write(id, test_w_buf, SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                     iot_cus_printf("[test][err] test cycle_count[%d] - write [%dth] sec failed!!!\n", | ||
|  |                         cycle_count, i+1); | ||
|  |                 } | ||
|  |             } else { | ||
|  |                 iot_cus_printf("[test][err] seek failed!!!\n"); | ||
|  |             } | ||
|  |         } | ||
|  |         time2 = gp_timer_get_current_val(0); | ||
|  |         if (time1 > time2) { | ||
|  |             time1 = (((uint32_t)(-1)) - time1 + time2); | ||
|  |         } else { | ||
|  |             time1 = (time2 - time1); | ||
|  |         } | ||
|  |         iot_cus_printf("test write passed. Takes %u ns.\n", time1); | ||
|  | 
 | ||
|  |         time1 = gp_timer_get_current_val(0); | ||
|  |         for (int i = 0; i < 10; i++) { | ||
|  |             if ( -1 != custom_ext_dev_seek(id, i * SPI_FLASH_SECTOR_SIZE, DEV_SEEK_SET)) { | ||
|  |                 if ( -1 == custom_ext_dev_read(id, test_r_buf, SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                     iot_cus_printf("[test][err] test cycle_count[%d] - read [%dth] sec failed!!!\n", | ||
|  |                         cycle_count, i+1); | ||
|  |                 } | ||
|  |             } else { | ||
|  |                     iot_cus_printf("[test][err] seek failed!!!\n"); | ||
|  |             } | ||
|  |             if (0 != os_mem_cmp(test_w_buf, test_r_buf, SPI_FLASH_SECTOR_SIZE)) { | ||
|  |                 iot_cus_printf("[test][err] wirte is not match.!!!\n"); | ||
|  |             } | ||
|  |         } | ||
|  |         time2 = gp_timer_get_current_val(0); | ||
|  |         if (time1 > time2) { | ||
|  |             time1 = (((uint32_t)(-1)) - time1 + time2); | ||
|  |         } else { | ||
|  |             time1 = (time2 - time1); | ||
|  |         } | ||
|  |         iot_cus_printf("test read passed. Takes %u ns.\n", time1); | ||
|  | 
 | ||
|  |         cycle_count++; | ||
|  |     } | ||
|  | 
 | ||
|  |     return ERR_OK; | ||
|  | } | ||
|  | 
 | ||
|  | uint8_t spi_falsh_test_whole_flash(uint32_t id, int in_addr1, int in_addr2) | ||
|  | { | ||
|  |     int addr = in_addr1, addr2 = in_addr2, cyc_cnt = 0; | ||
|  |     int rd_data, exp_data, sec_size, chip_size, err_offset; | ||
|  |     uint32_t time1, time2; | ||
|  |     uint32_t addr_start = in_addr1; | ||
|  |     uint32_t addr_end = in_addr2; | ||
|  | 
 | ||
|  |     iot_spi_flash_chip_info_t flash_info; | ||
|  | 
 | ||
|  |     if (ERR_OK != spi_flash_get_chipinfo(id, &flash_info)) { | ||
|  |         iot_cus_printf("[%s][err] get chip info failed!\n", __FUNCTION__); | ||
|  |         goto err_out; | ||
|  |     } | ||
|  | 
 | ||
|  |     sec_size = flash_info.sec_size; | ||
|  | 
 | ||
|  |     addr &= ~(sec_size - 1); | ||
|  |     addr2 &= ~(sec_size - 1); | ||
|  |     chip_size = flash_info.chip_size; | ||
|  | 
 | ||
|  |     if (addr2 + sec_size > chip_size) { | ||
|  |         cyc_cnt = chip_size - sec_size; | ||
|  |         iot_cus_printf("\r\nEnd offset overflow, set to %p\n", addr2, cyc_cnt); | ||
|  |         addr2 = cyc_cnt; | ||
|  |     } | ||
|  | 
 | ||
|  |     cyc_cnt = (addr2 - addr) / sec_size + 1; | ||
|  | 
 | ||
|  |     iot_cus_printf("\r\n[%s]Start full scan from sector %p to %p. Total %d sectors. \
 | ||
|  |         sec_size:0x%x\n", __FUNCTION__, addr, addr2, cyc_cnt, sec_size); | ||
|  | 
 | ||
|  |     while(1) { | ||
|  |         while ((cyc_cnt > 0) && (addr < g_spi_flash_obj.spi_flash_dev[id].chip.chip_size)) { | ||
|  |             iot_cus_printf("\r\ncycle %dth sector %p scan...", cycle_count, addr); | ||
|  |             time1 = gp_timer_get_current_val(0); | ||
|  |             if (0 != btm_executor_spi_flash_test_sector_rw_scan(id, addr, &err_offset, | ||
|  |                 &rd_data, &exp_data, 1, 0)) { | ||
|  |                 iot_cus_printf("\r\nflash full scan failed, error offset = %p, \
 | ||
|  |                     read data %p, expect data = %p.\n", | ||
|  |                     err_offset, rd_data, exp_data); | ||
|  |                 break; | ||
|  |             } | ||
|  |             time2 = gp_timer_get_current_val(0); | ||
|  |             if (time1 > time2) { | ||
|  |                 time1 = (((uint32_t)(-1)) - time1 + time2); | ||
|  |             } else { | ||
|  |                 time1 = (time2 - time1); | ||
|  |             } | ||
|  |             addr += sec_size; | ||
|  |             cyc_cnt--; | ||
|  |             iot_cus_printf("passed. Takes %u ns.", time1); | ||
|  |         } | ||
|  | 
 | ||
|  |         cycle_count++; | ||
|  |         cyc_cnt = (addr_end - addr_start) / sec_size + 1; | ||
|  |         addr = addr_start; | ||
|  |         os_delay(10); | ||
|  |     } | ||
|  | 
 | ||
|  |     iot_cus_printf("\r\nflash full scan done, all passed!\n", addr); | ||
|  | 
 | ||
|  |     return ERR_OK; | ||
|  | err_out: | ||
|  | 
 | ||
|  |     return ERR_FAIL; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | extern void wdg_deinit(uint32_t cpu); | ||
|  | uint8_t test_spi_flash_go() | ||
|  | { | ||
|  |     uint8_t flash_id = 0; | ||
|  |     iot_cus_print_config(true); | ||
|  |     iot_print_config(false); | ||
|  | 
 | ||
|  |     wdg_deinit(0); | ||
|  |     wdg_deinit(1); | ||
|  | 
 | ||
|  |     if (ERR_OK != iot_spi_flash_init()) { | ||
|  |         iot_cus_printf("[%s][err] flash init failed!\n", __FUNCTION__); | ||
|  |         goto err_out; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (-1 == (flash_id = custom_ext_dev_open())) { | ||
|  |         iot_cus_printf("[%s][err] flash open failed!\n", __FUNCTION__); | ||
|  |         goto err_out; | ||
|  |     } | ||
|  |     os_delay(10); | ||
|  | 
 | ||
|  |     //spi_falsh_test_sector(flash_id, 0x3000);
 | ||
|  |     //spi_falsh_test_whole_flash(flash_id, 0, g_spi_flash_obj.spi_flash_dev[0].chip.chip_size);
 | ||
|  |     spi_falsh_test_operate_sector(flash_id); | ||
|  | 
 | ||
|  |     return ERR_OK; | ||
|  | err_out: | ||
|  |     return ERR_FAIL; | ||
|  | } | ||
|  | #endif
 | ||
|  | 
 |