739 lines
24 KiB
C
739 lines
24 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 "hw_reg_api.h"
|
|
#include "chip_reg_base.h"
|
|
#include "apb_cache_reg.h"
|
|
|
|
#include "ahb.h"
|
|
#include "smc.h"
|
|
#include "sram.h"
|
|
#include "sfc.h"
|
|
#include "sfc_rf.h"
|
|
#include "flash.h"
|
|
#include "gp_timer.h"
|
|
#include "uart.h"
|
|
|
|
#include "iot_system.h"
|
|
#include "dbg_io.h"
|
|
#include "iot_clock.h"
|
|
|
|
#include "iot_io_api.h"
|
|
#include "iot_errno_api.h"
|
|
|
|
#include "dtest_printf.h"
|
|
|
|
#define DTEST_CACHE_RAM_CASE_RAM_FULL_RW (1 << 0)
|
|
#define DTEST_CACHE_RAM_CASE_CACHE_READ_EM (1 << 1)
|
|
#define DTEST_CACHE_RAM_CASE_CACHE_AS_RAM (1 << 2)
|
|
#define DTEST_CACHE_RAM_CASE_CACHE_DIRTY_MISS (1 << 3)
|
|
#define DTEST_CACHE_RAM_CASE_CACHE_LINE (1 << 4)
|
|
#define DTEST_CACHE_RAM_CASE_CACHE_ADDR_PROTECT (1 << 5)
|
|
#define DTEST_CACHE_RAM_CASE_SFC_SMC_IO_SHARE (1 << 6)
|
|
#define DTEST_CACHE_RAM_CASE_SFC_SMC_IO_REMAP (1 << 7)
|
|
|
|
#define DTEST_CACHE_RAM_RAM_SIZE 0x70000 //448kb
|
|
|
|
#define TEST_MEMORY_LENGTH(m) (m##_ENDADDR - m##_BASEADDR + 1)
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
|
|
|
typedef struct test_mem_block {
|
|
uint32_t start;
|
|
uint32_t length;
|
|
} test_mem_block_t;
|
|
|
|
test_mem_block_t test_mem_table[] = {
|
|
{ICACHE0_SMC_RAM_BASEADDR, TEST_MEMORY_LENGTH(ICACHE0_SMC_RAM)},
|
|
{ICACHE1_SMC_RAM_BASEADDR, TEST_MEMORY_LENGTH(ICACHE1_SMC_RAM)},
|
|
{ICACHE2_SMC_RAM_BASEADDR, TEST_MEMORY_LENGTH(ICACHE2_SMC_RAM)},
|
|
{DCACHE0_SMC_RAM_BASEADDR, TEST_MEMORY_LENGTH(DCACHE0_SMC_RAM)},
|
|
{DCACHE1_SMC_RAM_BASEADDR, TEST_MEMORY_LENGTH(DCACHE1_SMC_RAM)},
|
|
};
|
|
|
|
/**
|
|
* @brief: Test the data bus wiring in a memory region by
|
|
* performing a walking 1's test at a fixed address
|
|
* within that region. The address (and hence the
|
|
* memory region) is selected by the caller.
|
|
*
|
|
* @return: 0 if the test succeeds.
|
|
* A non-zero result is the first pattern that failed.
|
|
*/
|
|
static bool_t test_mem_data_bus(uint32_t addr)
|
|
{
|
|
/* Perform a walking 1's test at the given address */
|
|
for (uint8_t pattern = 1; pattern != 0; pattern <<= 1) {
|
|
/* Write the test pattern */
|
|
*(volatile uint8_t *)addr = pattern;
|
|
/* Read it back (immediately is okay for this test) */
|
|
if (*(volatile uint8_t *)addr != pattern) {
|
|
dprintf("[MEM_CHECK] data bus check fail, addr:0x%08x\n", addr);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief: Test the address bus wiring in a memory region by
|
|
* performing a walking 1's test on the relevant bits
|
|
* of the address and checking for aliasing. This test
|
|
* will find single-bit address failures such as stuck
|
|
* -high, stuck-low, and shorted pins. The base address
|
|
* and size of the region are selected by the caller.
|
|
*
|
|
* Notes: For best results, the selected base address should
|
|
* have enough LSB 0's to guarantee single address bit
|
|
* changes. For example, to test a 64-Kbyte region,
|
|
* select a base address on a 64-Kbyte boundary. Also,
|
|
* select the region size as a power-of-two--if at all
|
|
* possible.
|
|
*
|
|
* Returns: NULL if the test succeeds.
|
|
* A non-zero result is the first address at which an
|
|
* aliasing problem was uncovered. By examining the
|
|
* contents of memory, it may be possible to gather
|
|
* additional information about the problem.
|
|
*/
|
|
static bool_t test_mem_addr_bus(uint32_t addr, uint32_t length)
|
|
{
|
|
uint32_t addr_mask = (length / sizeof(uint32_t) - 1);
|
|
uint32_t test_offset;
|
|
uint32_t pattern = 0xAA;
|
|
uint32_t antipattern = 0x55;
|
|
|
|
/* Write the default pattern at each of the power-of-two offsets */
|
|
for (uint32_t offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
|
*(volatile uint8_t *)(addr + offset) = pattern;
|
|
}
|
|
|
|
/* Check for address bits stuck high. */
|
|
test_offset = 0;
|
|
*(volatile uint8_t *)(addr + test_offset) = antipattern;
|
|
for (uint32_t offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
|
if (*(volatile uint8_t *)(addr + offset) != pattern) {
|
|
dprintf("[MEM_CHECK] addr bus check fail, addr:0x%08x\n",
|
|
addr + offset);
|
|
return false;
|
|
}
|
|
}
|
|
*(volatile uint8_t *)(addr + test_offset) = pattern;
|
|
|
|
/* Check for address bits stuck low or shorted */
|
|
for (test_offset = 1; (test_offset & addr_mask) != 0; test_offset <<= 1) {
|
|
*(volatile uint8_t *)(addr + test_offset) = antipattern;
|
|
if (*(volatile uint8_t *)addr != pattern) {
|
|
dprintf("[MEM_CHECK] addr bus check fail, addr:0x%08x\n",
|
|
addr + test_offset);
|
|
return false;
|
|
}
|
|
for (uint32_t offset = 1; (offset & addr_mask) != 0; offset <<= 1) {
|
|
if ((*(volatile uint8_t *)(addr + offset) != pattern)
|
|
&& (offset != test_offset)) {
|
|
dprintf("[MEM_CHECK] addr bus check fail, addr:0x%08x\n",
|
|
addr + test_offset);
|
|
return false;
|
|
}
|
|
}
|
|
*(volatile uint8_t *)(addr + test_offset) = pattern;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @brief: Test the integrity of a physical memory device by
|
|
* performing an increment/decrement test over the
|
|
* entire region. In the process every storage bit
|
|
* in the device is tested as a zero and a one. The
|
|
* base address and the size of the region are
|
|
* selected by the caller.
|
|
*
|
|
* Returns: NULL if the test succeeds. Also, in that case, the
|
|
* entire memory region will be filled with zeros.
|
|
*
|
|
* A non-zero result is the first address at which an
|
|
* incorrect value was read back. By examining the
|
|
* contents of memory, it may be possible to gather
|
|
* additional information about the problem.
|
|
*/
|
|
static bool_t test_mem_device(uint32_t addr, uint32_t length)
|
|
{
|
|
uint32_t offset;
|
|
uint32_t word_len = length / sizeof(uint32_t);
|
|
uint32_t pattern;
|
|
uint32_t antipattern;
|
|
uint32_t *base_addr = (uint32_t *)addr;
|
|
|
|
/* Fill memory with a known pattern */
|
|
for (pattern = 1, offset = 0; offset < word_len; pattern++, offset++) {
|
|
base_addr[offset] = pattern;
|
|
}
|
|
|
|
/* Check each location and invert it for the second pass */
|
|
for (pattern = 1, offset = 0; offset < word_len; pattern++, offset++) {
|
|
if (base_addr[offset] != pattern) {
|
|
dprintf("[MEM_CHECK] device write check fail, addr:0x%08x\n",
|
|
addr + offset);
|
|
dprintf("[MEM_CHECK]\t write 0x%08x, read:0x%08x\n", pattern,
|
|
base_addr[offset]);
|
|
return false;
|
|
}
|
|
antipattern = ~pattern;
|
|
base_addr[offset] = antipattern;
|
|
}
|
|
|
|
/* Check each location for the inverted pattern and zero it. */
|
|
for (pattern = 1, offset = 0; offset < word_len; pattern++, offset++) {
|
|
antipattern = ~pattern;
|
|
if (base_addr[offset] != antipattern) {
|
|
dprintf("[MEM_CHECK] device invert check fail, addr:0x%08x\n",
|
|
addr + offset);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_cache_line_test()
|
|
{
|
|
uint32_t i;
|
|
|
|
dcase_start("cache data bus line and addr bus line\n");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(test_mem_table); i++) {
|
|
if (!test_mem_data_bus(test_mem_table[i].start)
|
|
|| !test_mem_addr_bus(test_mem_table[i].start, test_mem_table[i].length)
|
|
|| !test_mem_device(test_mem_table[i].start, test_mem_table[i].length)) {
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
/* there is a space reserved for ROM at the beginning of ram,
|
|
* and ram is divided into flash, IRAM and DRAM in link script
|
|
*/
|
|
static uint32_t dtest_cache_ram_ram_full_rw_test()
|
|
{
|
|
uint32_t i, j;
|
|
uint32_t len[3], addr[3];
|
|
uint8_t data_test = 0x55, data;
|
|
|
|
dcase_start("ram full read/write test(space outside code)\n");
|
|
|
|
addr[0] = AHB_RAM0_BASEADDR;
|
|
len[0] = (uint32_t)&_start - AHB_RAM0_BASEADDR;
|
|
addr[1] = (uint32_t)&_flash_end;
|
|
len[1] = (uint32_t)&_data - (uint32_t)&_flash_end;
|
|
addr[2] = (uint32_t)&_iram_end;
|
|
len[2] = DTEST_CACHE_RAM_RAM_SIZE - ((uint32_t)&_iram_end - AHB_RAM0_BASEADDR);
|
|
|
|
dprintf("read/write space range:\n");
|
|
for (i = 0; i < 3; i++) {
|
|
iot_printf("\tindex:%d, addr:0x%08x, len:0x%x\n", i, addr[i], len[i]);
|
|
}
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
for (j = addr[i]; j < len[i]; j++) {
|
|
*(uint8_t *)j = data_test;
|
|
}
|
|
for (j = addr[i]; j < len[i]; j++) {
|
|
data = *(uint8_t *)j;
|
|
if (data != data_test) {
|
|
dprintf("ram read data error, addr:0x%08x, rdata:0x%x, wdata:0x%x\n",
|
|
j, data, data_test);
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
data_test = 0xaa;
|
|
for (i = 0; i < 3; i++) {
|
|
for (j = addr[i]; j < len[i]; j++) {
|
|
*(uint8_t *)j = data_test;
|
|
}
|
|
for (j = addr[i]; j < len[i]; j++) {
|
|
data = *(uint8_t *)j;
|
|
if (data != data_test) {
|
|
dprintf("ram read data error, addr:0x%08x, rdata:0x%x, wdata:0x%x\n",
|
|
j, data, data_test);
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_cache_rw_ext_mem_test()
|
|
{
|
|
uint8_t i;
|
|
uint32_t addr_test = 0x00;
|
|
uint32_t data_test = 0x11223344, data;
|
|
|
|
dcase_start("cache read/write extern memory(flash/psram) test\n");
|
|
|
|
dprintf("write extern memory, test addr:0x%08x, test data:0x%08x\n", addr_test, data_test);
|
|
*(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test) = data_test;
|
|
cache_flush(0, addr_test + ICACHE0_SMC_RAM_BASEADDR, 32);
|
|
g_sfc_ctrl->erase_sector(addr_test, MOD_SW_MODE_DIS);
|
|
g_sfc_ctrl->write((uint8_t*)&data_test, addr_test, sizeof(data_test),
|
|
MOD_SFC_PROG_STAND, MOD_SW_MODE_DIS);
|
|
|
|
dprintf("read extern memory\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
// cache_clear(i);
|
|
data = *(uint32_t *)(test_mem_table[i].start + addr_test);
|
|
if (data != data_test) {
|
|
dprintf("cache read psram error, rdata:0x%08x, wdata:0x%08x\n", data, data_test);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
// cache_clear(i);
|
|
data = *(uint32_t *)(test_mem_table[i].start + 0x4000000 + addr_test);
|
|
if (data != data_test) {
|
|
dprintf("cache read flash error, rdata:0x%08x, wdata:0x%08x\n", data, data_test);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_cache_as_ram_test()
|
|
{
|
|
uint32_t i, err_cnt = 0;
|
|
uint32_t offset_test = 0x00;
|
|
uint32_t data_test = 0x11223344, data;
|
|
|
|
dcase_start("cache is configured for internal ram use\n");
|
|
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
cache_disable(i);
|
|
cache_enable(i);
|
|
cache_set_buffer_mode(i, AHB_CACHE_MODE_BUFFER);
|
|
cache_space_dis(i);
|
|
|
|
iot_delay_us(10);
|
|
*(uint32_t *)(test_mem_table[i].start + offset_test) = data_test;
|
|
data = *(uint32_t *)(test_mem_table[i].start + offset_test);
|
|
if (data != data_test) {
|
|
dprintf("cache as ram failed, test offset:0x%08x, rdata:0x%08x, wdata:0x%08x\n",
|
|
offset_test, data, data_test);
|
|
err_cnt++;
|
|
}
|
|
}
|
|
|
|
dprintf("restore cache as cache function\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
cache_disable(i);
|
|
cache_enable(i);
|
|
cache_set_buffer_mode(i, AHB_CACHE_MODE_CACHE);
|
|
cache_space_ena(i);
|
|
}
|
|
iot_delay_us(10);
|
|
data_test = 0xaabbccdd;
|
|
offset_test = 0x100000;
|
|
*(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + offset_test) = data_test;
|
|
cache_flush(0, offset_test, 32);
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + offset_test);
|
|
if (data != data_test) {
|
|
dprintf("restore cache failed, test offset:0x%08x, rdata:0x%08x, wdata:0x%08x\n",
|
|
offset_test, data, data_test);
|
|
err_cnt++;
|
|
}
|
|
|
|
if (err_cnt) {
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
} else {
|
|
dcase_success();
|
|
return ERR_OK;
|
|
}
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_cache_dirty_miss_test()
|
|
{
|
|
uint32_t addr_test = 0x100000;
|
|
volatile uint32_t data_test = 0x12345678, data_old1, data_old2, data_new;
|
|
|
|
dcase_start("cache(sfc) dirty(clear/invalidata) and miss test\n");
|
|
|
|
dprintf("cache invalidata operation test\n");
|
|
g_sfc_ctrl->erase_sector(addr_test, MOD_SW_MODE_DIS);
|
|
cache_clear(0);
|
|
data_old1 = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
|
|
g_sfc_ctrl->write((uint8_t*)&data_test, addr_test, sizeof(data_test),
|
|
MOD_SFC_PROG_STAND, MOD_SW_MODE_DIS);
|
|
data_old2 = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
cache_invalidate(0, addr_test + ICACHE0_SFC_RAM_BASEADDR, 32);
|
|
data_new = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
dprintf("invalidata test addr:0x%08x, test data:0x%08x, data_old1:0x%08x, "
|
|
"data_old2:0x%08x, data_new:0x%08x\n", addr_test, data_test, data_old1,
|
|
data_old2, data_new);
|
|
if (data_old1 != 0xffffffff) {
|
|
dprintf("sfc erase error\n");
|
|
goto fail;
|
|
}
|
|
if (data_old1 != data_old2) {
|
|
dprintf("cache dirty data error\n");
|
|
goto fail;
|
|
}
|
|
if (data_new != data_test) {
|
|
dprintf("cache incalidata operation failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dprintf("cache clear operation test\n");
|
|
g_sfc_ctrl->erase_sector(addr_test, MOD_SW_MODE_DIS);
|
|
cache_clear(0);
|
|
data_old1 = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
|
|
g_sfc_ctrl->write((uint8_t*)&data_test, addr_test, sizeof(data_test),
|
|
MOD_SFC_PROG_STAND, MOD_SW_MODE_DIS);
|
|
data_old2 = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
cache_clear(0);
|
|
data_new = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
dprintf("clear test addr:0x%08x, test data:0x%08x, data_old1:0x%08x, "
|
|
"data_old2:0x%08x, data_new:0x%08x\n", addr_test, data_test, data_old1,
|
|
data_old2, data_new);
|
|
if (data_old1 != 0xffffffff) {
|
|
dprintf("sfc erase error\n");
|
|
goto fail;
|
|
}
|
|
if (data_old1 != data_old2) {
|
|
dprintf("cache dirty data error\n");
|
|
goto fail;
|
|
}
|
|
if (data_new != data_test) {
|
|
dprintf("cache clear operation failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dprintf("cache miss and auto load test\n");
|
|
g_sfc_ctrl->erase_sector(addr_test, MOD_SW_MODE_DIS);
|
|
cache_clear(0);
|
|
data_old1 = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
|
|
g_sfc_ctrl->write((uint8_t*)&data_test, addr_test, sizeof(data_test),
|
|
MOD_SFC_PROG_STAND, MOD_SW_MODE_DIS);
|
|
/* icache0 has 32KB space, continuous reading of 32KB data will fill the cache */
|
|
for (uint32_t i = 1; i <= 0x8000; i++) {
|
|
data_old2 = *(uint8_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test + i);
|
|
}
|
|
data_new = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
dprintf("auto load test addr:0x%08x, test data:0x%08x, data_old1:0x%08x, "
|
|
"data_old2:0x%08x, data_new:0x%08x\n", addr_test, data_test, data_old1,
|
|
data_old2, data_new);
|
|
if (data_old1 != 0xffffffff) {
|
|
dprintf("sfc erase error\n");
|
|
goto fail;
|
|
}
|
|
if (data_new != data_test) {
|
|
dprintf("cache miss and auto load operation failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
//extern void cache_monitor_enable(uint8_t cache_id, uint8_t en);
|
|
//extern void cache_monitor_clear(uint8_t cache_id);
|
|
//extern uint8_t cache_monitor_state(uint8_t cache_id);
|
|
//extern void cache_monitor_set_acc_addr(uint8_t cache_id,
|
|
// uint32_t addr_s, uint32_t addr_e);
|
|
//extern void cache_monitor_set_mon_addr(uint8_t cache_id,
|
|
// uint32_t addr_s, uint32_t addr_e);
|
|
|
|
static uint32_t dtest_cache_ram_cache_addr_protect_test()
|
|
{
|
|
#if 0
|
|
uint8_t i, state;
|
|
uint32_t addr_acc_s = 0x00000000, addr_acc_e = 0x00008000;
|
|
uint32_t addr_mon_s = 0x00001000, addr_mon_e = 0x00002000;
|
|
|
|
dcase_start("cache address protection\n");
|
|
|
|
dprintf("enable all cache addr monitor function\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
cache_monitor_enable(i, 1);
|
|
cache_monitor_clear(i);
|
|
cache_monitor_set_acc_addr(i, addr_acc_s, addr_acc_e);
|
|
cache_monitor_set_mon_addr(i, addr_mon_s, addr_mon_e);
|
|
}
|
|
|
|
dprintf("using cache to access protected addresses\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
*(uint32_t *)(test_mem_table[i].start + addr_mon_s + 32) = 0x11223344;
|
|
cache_flush(i, addr_mon_s + 32, 32);
|
|
}
|
|
|
|
dprintf("check cross-border access status\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
state = cache_monitor_state(i);
|
|
if (!state) {
|
|
dprintf("cache:%d address out of bounds access not detected\n", i);
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
dprintf("disable all cache addr monitor function\n");
|
|
for (i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
cache_monitor_clear(i);
|
|
cache_monitor_enable(i, 0);
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
#endif
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_sfc_smc_io_share_test()
|
|
{
|
|
uint32_t temp;
|
|
uint32_t addr_test = 0x100000;
|
|
uint32_t data, data_flash = 0x11223344, data_psram = 0xaabbccdd;
|
|
|
|
dcase_start("sfc and smc io share\n");
|
|
|
|
dprintf("init flash/psram data\n");
|
|
g_sfc_ctrl->erase_sector(addr_test, MOD_SW_MODE_DIS);
|
|
g_sfc_ctrl->write((uint8_t*)&data_flash, addr_test, sizeof(data_flash), MOD_SFC_PROG_STAND, MOD_SW_MODE_DIS);
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
if (data != data_flash) {
|
|
dprintf("flash write/read failed\n");
|
|
goto fail;
|
|
}
|
|
*(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test) = data_psram;
|
|
cache_flush(0, addr_test, 32);
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test);
|
|
if (data != data_psram) {
|
|
dprintf("psram write/read failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dprintf("enable io share, need init flash again\n");
|
|
|
|
temp = SFC_READ_REG(CFG_SFC_DBG_ADDR);
|
|
REG_FIELD_SET(SFC_SMC_IO_SHARE, temp, 1);
|
|
REG_FIELD_SET(SFC_SMC_ARB_SHARE, temp, 1);
|
|
SFC_WRITE_REG(CFG_SFC_DBG_ADDR, temp);
|
|
iot_delay_us(1000);
|
|
|
|
uint8_t id[8] = {0};
|
|
sfc_qspi_get_id_mult(id, MOD_SFC_SERIAL);
|
|
dprintf("Manufacturer ID(serial):0x%x, device id:0x%x\n",id[0], id[1]);
|
|
flash_init(1);
|
|
sfc_set_endian_mode(1);
|
|
|
|
dprintf("read flash/psram data again\n");
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
if (data != data_flash) {
|
|
dprintf("flash data read failed\n");
|
|
goto fail;
|
|
}
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test);
|
|
if (data != data_psram) {
|
|
dprintf("psram data read failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dprintf("disable io share\n");
|
|
temp = SFC_READ_REG(CFG_SFC_DBG_ADDR);
|
|
REG_FIELD_SET(SFC_SMC_IO_SHARE, temp, 0);
|
|
REG_FIELD_SET(SFC_SMC_ARB_SHARE, temp, 0);
|
|
SFC_WRITE_REG(CFG_SFC_DBG_ADDR, temp);
|
|
iot_delay_us(1000);
|
|
|
|
dprintf("read flash/psram data again\n");
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
if (data != data_flash) {
|
|
dprintf("flash data read failed\n");
|
|
goto fail;
|
|
}
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test);
|
|
if (data != data_psram) {
|
|
dprintf("psram data read failed\n");
|
|
goto fail;
|
|
}
|
|
|
|
dcase_success();
|
|
return ERR_OK;
|
|
fail:
|
|
dcase_failed();
|
|
return ERR_FAIL;
|
|
}
|
|
|
|
static uint32_t dtest_cache_ram_sfc_smc_io_remap_test()
|
|
{
|
|
volatile uint32_t data;
|
|
/* QPI mode requires 4 address lines. Staggering 1 helps to observe the timing */
|
|
uint32_t addr_test = 0x8421;
|
|
uint32_t cnt = 1000;
|
|
|
|
(void)data;
|
|
/* It is necessary to manually change the register
|
|
* and check whether the timing is correct on the logic analyzer
|
|
*/
|
|
while (cnt--) {
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test);
|
|
dprintf("get psram data:0x%08x\n");
|
|
|
|
cache_clear(0);
|
|
data = *(uint32_t *)(ICACHE0_SFC_RAM_BASEADDR + addr_test);
|
|
dprintf("get flash data:0x%08x\n");
|
|
}
|
|
|
|
return ERR_OK;
|
|
}
|
|
|
|
static void dtest_cache_ram_main()
|
|
{
|
|
uint32_t case_group = 0, error_cnt = 0;
|
|
|
|
dbg_uart_init();
|
|
|
|
dconfig();
|
|
dstart();
|
|
dversion();
|
|
|
|
if (dtest_get_case_group(&case_group) < 0) {
|
|
case_group = 0xffffffff;
|
|
}
|
|
dprintf("get case group:0x%08X\n", case_group);
|
|
|
|
dprintf("init gptimer0 for delay\n");
|
|
gp_timer_init();
|
|
gp_timer_set(0, 0xffffffff, 0);
|
|
gp_timer_start(0);
|
|
|
|
dprintf("reset emc\n");
|
|
ahb_emc_disable();
|
|
ahb_emc_enable();
|
|
ahb_emc_reset();
|
|
|
|
dprintf("initialize psram\n");
|
|
sram_qspi_init();
|
|
sram_qspi_enter();
|
|
hal_smc_qspi_quad_cfg(0);
|
|
|
|
dprintf("init sfc and flash\n");
|
|
flash_init(1);
|
|
sfc_set_endian_mode(1);
|
|
|
|
dprintf("initialize all of the cache\n");
|
|
for (uint8_t i = AHB_CACHE_I0; i < AHB_CACHE_MAX; i++) {
|
|
cache_disable(i);
|
|
cache_enable(i);
|
|
cache_fill_valid_space(i);
|
|
}
|
|
|
|
if (case_group & DTEST_CACHE_RAM_CASE_RAM_FULL_RW) {
|
|
if (dtest_cache_ram_ram_full_rw_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
if (case_group & DTEST_CACHE_RAM_CASE_CACHE_READ_EM) {
|
|
if (dtest_cache_ram_cache_rw_ext_mem_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
if (case_group & DTEST_CACHE_RAM_CASE_CACHE_AS_RAM) {
|
|
if (dtest_cache_ram_cache_as_ram_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
if (case_group & DTEST_CACHE_RAM_CASE_CACHE_DIRTY_MISS) {
|
|
if (dtest_cache_ram_cache_dirty_miss_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
if (case_group & DTEST_CACHE_RAM_CASE_CACHE_LINE) {
|
|
if (dtest_cache_ram_cache_line_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
/* kl3 hardware is not support cache address protect function */
|
|
if (0) {
|
|
if (dtest_cache_ram_cache_addr_protect_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
/* KL3 does not adopt IO share scheme, and image does not support IO share */
|
|
if (0) {
|
|
if (dtest_cache_ram_sfc_smc_io_share_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
/* Manual test */
|
|
if (0) {
|
|
if (dtest_cache_ram_sfc_smc_io_remap_test()) {
|
|
error_cnt++;
|
|
}
|
|
}
|
|
|
|
if (error_cnt) {
|
|
dprintf("cache_ram dtest failed\n");
|
|
} else {
|
|
dprintf("cache_ram dtest succeed\n");
|
|
}
|
|
|
|
dend();
|
|
}
|
|
|
|
int main(void) {
|
|
dtest_cache_ram_main();
|
|
return 0;
|
|
}
|
|
|