379 lines
11 KiB
C
379 lines
11 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 "sram.h"
|
||
|
#include "smc.h"
|
||
|
#include "ahb.h"
|
||
|
#include "gp_timer.h"
|
||
|
|
||
|
#include "uart.h"
|
||
|
#include "dbg_io.h"
|
||
|
|
||
|
#include "iot_io_api.h"
|
||
|
#include "os_mem_api.h"
|
||
|
#include "iot_errno_api.h"
|
||
|
|
||
|
#include "dtest_printf.h"
|
||
|
|
||
|
#define DTEST_SMC_CASE_GET_SIZE (1 << 0)
|
||
|
#define DTEST_SMC_CASE_API_RW (1 << 1)
|
||
|
#define DTEST_SMC_CASE_CACHE_RW (1 << 2)
|
||
|
#define DTEST_SMC_CASE_FULL_RW (1 << 3)
|
||
|
|
||
|
/* test PSRAM size using write loopback mechanism */
|
||
|
uint32_t dtest_smc_get_psram_size_test(uint8_t *size)
|
||
|
{
|
||
|
uint8_t i;
|
||
|
uint32_t addr_test, data_test, data;
|
||
|
|
||
|
dcase_start("get psram size test\n");
|
||
|
|
||
|
// cache_invalidate(0, ICACHE0_SMC_RAM_BASEADDR, 32);
|
||
|
cache_clear(0);
|
||
|
*(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR) = 0x0;
|
||
|
cache_flush(0, 0x00, 32);
|
||
|
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
addr_test = 0x100000 * i;
|
||
|
uint8_t temp = i ^ 0x55;
|
||
|
data_test = (temp << 24) | (temp << 16) | (temp << 8) | temp;
|
||
|
dprintf("test addr:0x%08x, data:0x%08x\n", addr_test, data_test);
|
||
|
*(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test) = data_test;
|
||
|
cache_flush(0, addr_test, 32);
|
||
|
|
||
|
// cache_invalidate(0, ICACHE0_SMC_RAM_BASEADDR, 32);
|
||
|
cache_clear(0);
|
||
|
data = *(volatile uint32_t *)(ICACHE0_SMC_RAM_BASEADDR);
|
||
|
if (addr_test == 0x00) {
|
||
|
if (data != data_test) {
|
||
|
dprintf("addr(0x00) write and read error, psram not working\n");
|
||
|
*size = 0;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
if (data == data_test) {
|
||
|
dprintf("write data loopback\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i == 32) {
|
||
|
dprintf("no matching psram size found\n");
|
||
|
goto fail;
|
||
|
}
|
||
|
|
||
|
dprintf("get psram size:%d\n", i);
|
||
|
dcase_success();
|
||
|
return ERR_OK;
|
||
|
fail:
|
||
|
dcase_failed();
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
|
||
|
uint32_t dtest_smc_api_test()
|
||
|
{
|
||
|
int i = 0;
|
||
|
uint8_t rdata[0x40] = {0};
|
||
|
uint8_t wdata[0x40] = {0};
|
||
|
uint8_t data_test = 0x55;
|
||
|
uint32_t addr_test = 0x10000;
|
||
|
|
||
|
dcase_start("smc api read/write test\n");
|
||
|
|
||
|
dprintf("init test data with 0x%x\n", data_test);
|
||
|
os_mem_set(wdata, data_test, sizeof(wdata));
|
||
|
|
||
|
while(sram_qspi_is_busy() != HAL_SRAM_OK) {
|
||
|
dprintf("FLASH IS Busy Now!\n");
|
||
|
}
|
||
|
|
||
|
/* spi mode */
|
||
|
dprintf("use spi mode to read/write psram\n");
|
||
|
|
||
|
sram_qspi_exit();
|
||
|
while (sram_qspi_is_busy() != HAL_SRAM_OK);
|
||
|
dprintf("qpi exit succeed\n");
|
||
|
|
||
|
dprintf("spi write data\n");
|
||
|
sram_qspi_write(wdata, addr_test, sizeof(wdata));
|
||
|
while(sram_qspi_is_busy() != HAL_SRAM_OK);
|
||
|
|
||
|
dprintf("spi read data\n");
|
||
|
sram_qspi_read(rdata, addr_test, sizeof(rdata));
|
||
|
while(sram_qspi_is_busy() != HAL_SRAM_OK);
|
||
|
for (i = 0; i < sizeof(wdata); i++) {
|
||
|
if (wdata[i] != rdata[i]) {
|
||
|
dprintf("spi mode read data err, index:%d, wdata:%x, rdata:%x\n", i, wdata[i], rdata[i]);
|
||
|
goto fail;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* qpi mode */
|
||
|
data_test = 0xaa;
|
||
|
dprintf("use qpi mode to read/write psram, init test data with 0x%x\n", data_test);
|
||
|
os_mem_set(wdata, data_test, sizeof(wdata));
|
||
|
|
||
|
sram_qspi_enter();
|
||
|
while(sram_qspi_is_busy() != HAL_SRAM_OK);
|
||
|
dprintf("qspi enter succeed\n");
|
||
|
|
||
|
dprintf("qpi write data\n");
|
||
|
sram_qspi_quad_write(wdata, addr_test, sizeof(wdata));
|
||
|
while(sram_qspi_is_busy());
|
||
|
|
||
|
dprintf("qpi read data\n");
|
||
|
os_mem_set(rdata, 0x00, sizeof(rdata));
|
||
|
|
||
|
sram_qspi_quad_read(rdata, addr_test, sizeof(rdata));
|
||
|
while(sram_qspi_is_busy() != HAL_SRAM_OK);
|
||
|
for (i = 0; i < sizeof(wdata); i++) {
|
||
|
if (wdata[i] != rdata[i]) {
|
||
|
dprintf("qpi mode read data err, index:%d, wdata:%x, rdata:%x\n", i, wdata[i], rdata[i]);
|
||
|
goto fail;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dcase_success();
|
||
|
return ERR_OK;
|
||
|
fail:
|
||
|
dcase_failed();
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
|
||
|
uint32_t dtest_smc_cache_rw_test()
|
||
|
{
|
||
|
uint32_t i = 0, data = 0, error = 0, test_len = 0x1000, addr_test = 0x000000;
|
||
|
|
||
|
dcase_start("smc cache read/write test\n");
|
||
|
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
*((volatile uint8_t*)(DCACHE0_SMC_RAM_BASEADDR + addr_test + i)) = i % 0xff;
|
||
|
}
|
||
|
cache_flush(AHB_CACHE_D0, addr_test, test_len);
|
||
|
|
||
|
dprintf("write/read sram by icache0\n");
|
||
|
cache_invalidate(AHB_CACHE_I0, addr_test, test_len);
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
data = *(volatile uint8_t *)(ICACHE0_SMC_RAM_BASEADDR + addr_test + i);
|
||
|
if (data != (i % 0xff)) {
|
||
|
dprintf("ERROR icache0 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dprintf("write/read sram by icache1\n");
|
||
|
cache_invalidate(AHB_CACHE_I1, addr_test, test_len);
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
data = *(volatile uint8_t *)(ICACHE1_SMC_RAM_BASEADDR + addr_test + i);
|
||
|
if (data != (i % 0xff)) {
|
||
|
dprintf("ERROR icache1 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dprintf("write/read sram by icache2\n");
|
||
|
cache_invalidate(AHB_CACHE_I2, addr_test, test_len);
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
data = *(volatile uint8_t *)(ICACHE2_SMC_RAM_BASEADDR + addr_test + i);
|
||
|
if (data != (i % 0xff)) {
|
||
|
dprintf("ERROR icache2 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dprintf("write/read sram by dcache0\n");
|
||
|
cache_invalidate(AHB_CACHE_D0, addr_test, test_len);
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
data = *(volatile uint8_t *)(DCACHE0_SMC_RAM_BASEADDR + addr_test + i);
|
||
|
if (data != (i % 0xff)) {
|
||
|
dprintf("ERROR dcache0 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dprintf("write/read sram by dcache1\n");
|
||
|
cache_invalidate(AHB_CACHE_D1, addr_test, test_len);
|
||
|
for (i = 0; i < test_len; i++) {
|
||
|
data = *(volatile uint8_t *)(DCACHE1_SMC_RAM_BASEADDR + addr_test + i);
|
||
|
if (data != (i % 0xff)) {
|
||
|
dprintf("ERROR dcache1 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 == error) {
|
||
|
dcase_success();
|
||
|
return ERR_OK;
|
||
|
}else {
|
||
|
dcase_failed();
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t dtest_smc_psram_full_rw_test(uint8_t psram_size)
|
||
|
{
|
||
|
uint32_t i = 0, error = 0, temp;
|
||
|
uint8_t data_test = 0x55, data;
|
||
|
uint32_t len_test = psram_size * 0x100000;
|
||
|
uint32_t time_old = 0, time_new = 0, time_use;
|
||
|
|
||
|
dcase_start("psram full read/write test\n");
|
||
|
|
||
|
/* icache_wr_auto_load = 0, it can significantly speed up the reading and
|
||
|
* writing of large amounts of data.
|
||
|
* In this test, the cache has no other work, and almost no miss will
|
||
|
* be generated, so no significant reduction in time is observed(4m - 14678us).
|
||
|
*/
|
||
|
temp = CACHE0_READ_REG(CFG_CACHE_CTR0_ADDR);
|
||
|
REG_FIELD_SET(ICACHE_WR_AUTO_LOAD, temp, 0);
|
||
|
CACHE0_WRITE_REG(CFG_CACHE_CTR0_ADDR, temp);
|
||
|
|
||
|
time_old = gp_timer_get_current_val(0);
|
||
|
|
||
|
dprintf("write psram, data:0x%x, len:0x%x\n", data_test, len_test);
|
||
|
cache_clear(AHB_CACHE_I0);
|
||
|
for (i = 0; i < len_test; i++) {
|
||
|
*((volatile uint8_t*)(ICACHE0_SMC_RAM_BASEADDR + i)) = i % 0xff;
|
||
|
}
|
||
|
|
||
|
dprintf("read psram\n");
|
||
|
cache_invalidate(AHB_CACHE_I0, 0x00, 0x8000);
|
||
|
for (i = 0; i < len_test; i++) {
|
||
|
data = *(volatile uint8_t *)(ICACHE0_SMC_RAM_BASEADDR + i);
|
||
|
if (data != data_test) {
|
||
|
dprintf("ERROR icache0 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
data_test = 0xaa;
|
||
|
dprintf("write psram, data:0x%x, len:0x%x\n", data_test, len_test);
|
||
|
cache_clear(AHB_CACHE_I0);
|
||
|
for (i = 0; i < len_test; i++) {
|
||
|
*((volatile uint8_t*)(ICACHE0_SMC_RAM_BASEADDR + i)) = i % 0xff;
|
||
|
}
|
||
|
|
||
|
dprintf("read psram\n");
|
||
|
cache_invalidate(AHB_CACHE_I0, 0x00, 0x8000);
|
||
|
for (i = 0; i < len_test; i++) {
|
||
|
data = *(volatile uint8_t *)(ICACHE0_SMC_RAM_BASEADDR + i);
|
||
|
if (data != data_test) {
|
||
|
dprintf("ERROR icache0 sram read: i:%d, data:%02x\n", i, data);
|
||
|
error++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
time_new = gp_timer_get_current_val(0);
|
||
|
time_use = (time_old < time_new) ? (time_new - time_old) :
|
||
|
(0xffffffff - time_old + time_new);
|
||
|
dprintf("full read/write complete, it takes %d us\n", time_use);
|
||
|
|
||
|
temp = CACHE0_READ_REG(CFG_CACHE_CTR0_ADDR);
|
||
|
REG_FIELD_SET(ICACHE_WR_AUTO_LOAD, temp, 1);
|
||
|
CACHE0_WRITE_REG(CFG_CACHE_CTR0_ADDR, temp);
|
||
|
|
||
|
if (0 == error) {
|
||
|
dcase_success();
|
||
|
return ERR_OK;
|
||
|
}else {
|
||
|
dcase_failed();
|
||
|
return ERR_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void dtest_smc_main()
|
||
|
{
|
||
|
uint32_t case_group = 0, error_cnt = 0;
|
||
|
uint8_t psram_size = 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);
|
||
|
|
||
|
gp_timer_init();
|
||
|
gp_timer_set(0, 0xffffffff, 0);
|
||
|
gp_timer_start(0);
|
||
|
|
||
|
/* reset emc */
|
||
|
dprintf("reset emc\n");
|
||
|
ahb_emc_disable();
|
||
|
ahb_emc_enable();
|
||
|
ahb_emc_reset();
|
||
|
|
||
|
/* init psram */
|
||
|
dprintf("initialize psram\n");
|
||
|
sram_qspi_init();
|
||
|
sram_qspi_enter();
|
||
|
hal_smc_qspi_quad_cfg(0);
|
||
|
|
||
|
/* init cache */
|
||
|
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_SMC_CASE_GET_SIZE) {
|
||
|
if (dtest_smc_get_psram_size_test(&psram_size)) {
|
||
|
error_cnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* only buffer mode, register mode will be failed */
|
||
|
if (case_group & DTEST_SMC_CASE_API_RW) {
|
||
|
if (dtest_smc_api_test()) {
|
||
|
error_cnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (case_group & DTEST_SMC_CASE_CACHE_RW) {
|
||
|
if (dtest_smc_cache_rw_test()) {
|
||
|
error_cnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (case_group & DTEST_SMC_CASE_FULL_RW) {
|
||
|
if (dtest_smc_psram_full_rw_test(psram_size)) {
|
||
|
error_cnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (error_cnt) {
|
||
|
dprintf("smc dtest failed\n");
|
||
|
} else {
|
||
|
dprintf("smc dtest succeed\n");
|
||
|
}
|
||
|
|
||
|
dend();
|
||
|
}
|
||
|
|
||
|
int main(void) {
|
||
|
dtest_smc_main();
|
||
|
return 0;
|
||
|
}
|
||
|
|