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
 | 
						|
 |