Files
2026-08-24 10:03:24 +08:00

552 lines
18 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include "ddr.h"
#include "common.h"
#include "register.h"
#include "FreeRTOS.h"
#include "task.h"
#include "soc.h"
#include "suspend_debug_ddr.h"
#include "../timer_source/timer_source.h"
#define DDR_SUSPEND_VERSION "AML_T5W_DDR_1_2"
//#define ENABLE_DMC_DDR_TEST
#ifdef ENABLE_DMC_DDR_TEST
#define TEST_START_ADDRESS 0x10000000
#define TEST_END_ADDRESS 0x20000000
#endif
#define timere_read() REG32(TIMERE_LOW_REG)
/* io defines */
#define wr_reg(addr, val) ((*((volatile uint32_t *)(addr))) = (val))
#define rd_reg(addr) (*((volatile uint32_t *)(addr)))
/*clear [mask] 0 bits in [addr], set these 0 bits with [value] corresponding bits*/
#define modify_reg(addr, value, mask) wr_reg(addr, ((rd_reg(addr) & (mask)) | (value)))
#define wait_set(addr, loc) \
do { \
} while (0 == (rd_reg(addr) & (1 << loc)))
#define wait_clr(addr, loc) \
do { \
} while ((1U << loc) == (rd_reg(addr) & (1U << loc)))
#define wait_equal(addr, data) \
do { \
} while (data != (rd_reg(addr)))
//#define _udelay(tim) vTaskDelay(tim)
void _udelay(uint32_t delay_us)
{
unsigned int time1;
unsigned int time2;
time1 = timere_read();
do {
time2 = timere_read();
} while ((time2 - time1) < delay_us);
}
//#define udelay(tim) _udelay(tim)
//unsigned int g_nAPDSet = 0;
#ifdef ENABLE_DMC_DDR_TEST
static unsigned int dmc_ddr_test(unsigned int start_add, unsigned int write_enable,
unsigned int read_enable, unsigned int read_compare, unsigned int test_end_add,
unsigned int pattern, unsigned int seed)
{
seed = 2;
#define DATA_LOOP_PATTERN_INDEX (4 + 32) //0xff
unsigned int dmc_test_sts = 0;
unsigned int dmc_error = 0;
//unsigned int pattern_select = 0;
unsigned int pattern_value = 0;
unsigned int pattern_inv_value = 0;
dmc_error = 0;
{
test_end_add = test_end_add - 4; //sha must bit 0-6 ==ff;
}
wr_reg(DMC_TEST_STA, start_add); // RESET FIFOS //0x03d81e3f
wr_reg(DMC_TEST_EDA, test_end_add); //0x07d81e3f
if (pattern == 0) {
wr_reg(DMC_TEST_WD0, 0xaa5555aa);
wr_reg(DMC_TEST_WD1, 0x55aaaa55);
wr_reg(DMC_TEST_WD2, 0);
wr_reg(DMC_TEST_WD3, 0xffffffff);
wr_reg(DMC_TEST_WD4, 0);
wr_reg(DMC_TEST_WD5, 0x0000ffff);
wr_reg(DMC_TEST_WD6, 0xffff0000);
wr_reg(DMC_TEST_WD7, 0x33cccc33);
wr_reg(DMC_TEST_WD0 + 32, 0xaa5555aa);
wr_reg(DMC_TEST_WD1 + 32, 0x55aaaa55);
wr_reg(DMC_TEST_WD2 + 32, 0);
wr_reg(DMC_TEST_WD3 + 32, 0xffffffff);
wr_reg(DMC_TEST_WD4 + 32, 0);
wr_reg(DMC_TEST_WD5 + 32, 0x0000ffff);
wr_reg(DMC_TEST_WD6 + 32, 0xffff0000);
wr_reg(DMC_TEST_WD7 + 32, 0x33cccc33);
} else if (pattern < 33) {
wr_reg(DMC_TEST_WD0, ((1 << (pattern - 1)) + seed));
wr_reg(DMC_TEST_WD1, ((2 << (pattern - 1)) + seed));
wr_reg(DMC_TEST_WD2, ((3 << (pattern - 1)) + seed));
wr_reg(DMC_TEST_WD3, ((4 << (pattern - 1)) + seed));
wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1))));
wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1))));
wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1))));
wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1))));
if (pattern > 16) {
wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1)) + 0x01010101));
} else if (pattern > 1) {
wr_reg(DMC_TEST_WD4, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD5, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD6, ((4 << (pattern - 1)) + 0x01010101));
wr_reg(DMC_TEST_WD7, ((4 << (pattern - 1)) + 0x01010101));
}
} else {
//pattern_select = pattern - 33;
pattern_value = 1;// cpu_ddr_test_init_pattern_generator(pattern_select, 0);
pattern_inv_value = ~pattern_value;
for (char counter = 0; counter < 32; ) {
wr_reg((DMC_TEST_WD0 + counter), pattern_value);
counter = counter + 4;
wr_reg((DMC_TEST_WD0 + counter), pattern_inv_value);
if (counter == 16)
wr_reg((DMC_TEST_WD0 + counter), 0);
counter = counter + 4;
}
for (char counter = 0; counter < 32; ) { //for g12b-revb register not continuous
wr_reg((DMC_TEST_WD8 + counter), pattern_value);
counter = counter + 4;
wr_reg((DMC_TEST_WD8 + counter), pattern_inv_value);
if (counter == 16)
wr_reg((DMC_TEST_WD0 + counter), ~0);
counter = counter + 4;
}
}
//must clear watchdog and done flag jiaxing debug 2016_12_07
wr_reg(DMC_TEST_STS, 0x8000001f);
//wdg should >rfc value ,use dmc clk count.
wr_reg(DMC_TEST_WDG, 0xf000f000);
//should repeat 1 times for read ,all will fail when data increase jiaxing debug 20180322
if ((pattern == 1) || ((pattern < 33) && pattern))
wr_reg(DMC_TEST_CTRL, (1 << 31) | (read_compare << 27) | (0 << 28) | (0 << 25) |
(1 << 24) | (0 << 20) | (1 << 23) | (0x0 << 16) | (0 << 8) | (0x428) |
(3 << 18) | (write_enable << 30) | (read_enable << 29));
else
wr_reg(DMC_TEST_CTRL, (1 << 31) | (read_compare << 27) | (0 << 28) | (1 << 24) |
(0x0 << 16) | (0 << 18) | (0x0 << 0) | (0 << 8) | (0x428) | (3 << 18) |
(write_enable << 30) | (read_enable << 29));
do {
mdelay(100);
dmc_test_sts = (rd_reg(DMC_TEST_STS));
printf("\n dmc_test_sts %08x\n", dmc_test_sts);
} while (!(dmc_test_sts & 0xc0000000));
wr_reg(DMC_TEST_CTRL, 0x00000000);
if ((dmc_test_sts & 0x40000000))
dmc_error = 1;
else
//can not deter write trigger ,or can not quickly recover dmc with phy? 2016_12_12
if (dmc_test_sts & 0x1)
dmc_error = 1;
dmc_error = dmc_error + (rd_reg(DMC_TEST_ERR_CNT));
dmc_test_sts = (rd_reg(DMC_TEST_STS));
wr_reg(DMC_TEST_STS, dmc_test_sts);
//must write sts value to clear watchdog and done flag
if (dmc_error) {
for (unsigned int counter1 = 0; counter1 < (DMC_TEST_RDRSP_ADDR + 4 - DMC_TEST_STA);) {
printf("\n counter %08x %08x", counter1, (rd_reg(DMC_TEST_STA + (counter1))));
counter1 = counter1 + 4;
}
//clear read buffer dmc test reset
wr_reg(DMC_SOFT_RST, (rd_reg(DMC_SOFT_RST)) & (~((1 << 29) | (1 << 24))));
udelay(1);
wr_reg(DMC_SOFT_RST, (rd_reg(DMC_SOFT_RST)) | ((1 << 29)) | (1 << 24));
udelay(1);
}
return dmc_error;
}
//unsigned int apb_sec_ctrl = 0;
//#define DDR_APB_SEC_CTRL ((0x00f0 << 2) + 0xff639000)
#endif
#define DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START 2
unsigned int test_loops;
unsigned int apd_value;
#define PHY_T5_PHY_DDR_TYPE_ADD 0xfe002000
//bit4:1 1 ddr3 2 ddr4 4 lpddr3 8 lpddr4
#define PHY_T5_DDR4_MR2_ADD 0xfe000108
//BIT0-13 mr2
#define DMC_DDR_CTRL_ADD ((0x0100 << 2) + 0xff639000)
//bit 24:22 3'b000 : ddr3 mode.
//3'b001 : ddr4 mode.
//3'b010 : lpddr3 mode.
//3'b011 : lpddr4 mode.
#define CONFIG_DDR_TYPE_DDR3 0
#define CONFIG_DDR_TYPE_DDR4 1
#define CONFIG_DDR_TYPE_LPDDR4 2
#define CONFIG_DDR_TYPE_LPDDR3 3
#define CONFIG_DDR_TYPE_LPDDR2 4
#define CONFIG_DDR_TYPE_LPDDR4X 5
#define ENABLE_SET_MR2_REFRESH_RATE 1
#ifdef ENABLE_SET_MR2_REFRESH_RATE
unsigned int global_ddr4_mr2_value;
enum ddr4_mr2_fresh {
DDR4_MR2_FRESH_1X = 0, //
DDR4_MR2_FRESH_0_5X = 1, //
DDR4_MR2_FRESH_2X = 2, //
DDR4_MR2_FRESH_AUTO_MODE = 3 //0_25X
};
static char get_dram_type(void)
{
unsigned int ddr_ctrl_value = rd_reg(PHY_T5_PHY_DDR_TYPE_ADD);
ddr_ctrl_value = (ddr_ctrl_value >> 1) & 0xf;
if (ddr_ctrl_value == 1)
return CONFIG_DDR_TYPE_DDR3;
else if (ddr_ctrl_value == 2)
return CONFIG_DDR_TYPE_DDR4;
else if (ddr_ctrl_value == 4)
return CONFIG_DDR_TYPE_LPDDR3;
else if (ddr_ctrl_value == 8)
return CONFIG_DDR_TYPE_LPDDR4;
else
return CONFIG_DDR_TYPE_DDR4;
}
static unsigned int update_and_get_ddr4_mr2_refresh_value(void)
{
unsigned int ddr4_mr2_value = rd_reg(PHY_T5_DDR4_MR2_ADD);
global_ddr4_mr2_value = ddr4_mr2_value;
ddr4_mr2_value = (ddr4_mr2_value >> 0) & 0x3fff;
return ddr4_mr2_value;
}
static void set_dram_mrs(char rank_index, char mrs_index, uint16_t reg_value, char ddr_type)
{
wr_reg(DMC_DRAM_CMD_TIME, 0xa000a);
char calc_mrs_index = 0;
char calc_data_cycles = 2;
if ((ddr_type == CONFIG_DDR_TYPE_DDR3) || (ddr_type == CONFIG_DDR_TYPE_LPDDR3)) {
calc_mrs_index = ((mrs_index));
calc_data_cycles = 2;
}
if (ddr_type == CONFIG_DDR_TYPE_DDR4) {
calc_mrs_index = ((mrs_index & 0x3) << 0) | (((mrs_index >> 2) & 0x3) << 3);
calc_data_cycles = 2;
}
if (ddr_type == CONFIG_DDR_TYPE_LPDDR4) {
calc_mrs_index = ((mrs_index));
calc_data_cycles = 4;
}
wr_reg(DMC_DRAM_CMD_CODE, ((rank_index + 1) << 24) |
((calc_data_cycles - 1) << 26) |
((calc_mrs_index) << 16) |
(reg_value));
wr_reg(DMC_DRAM_CMD, 0);
wr_reg(DMC_DRAM_CMD, 1);
while ((((rd_reg(DMC_DRAM_CMD) >> 31) & 0x1) != 1))
;
printf("aml log : DDR suspend.mrs_index = %x\n", mrs_index);
printf("aml log : DDR suspend.reg_value = %x\n", reg_value);
} /* set_dram_mrs */
#endif
void vDDR_suspend(uint32_t st_f)
{
(void)st_f;
#ifdef ENABLE_DMC_DDR_TEST
unsigned int ddr_bist_test_error = 0;
ddr_bist_test_error = dmc_ddr_test(TEST_START_ADDRESS, 1, 0, 0, TEST_END_ADDRESS, 1, 0);
ddr_bist_test_error = dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0);
if (ddr_bist_test_error) {
ddr_bist_test_error =
dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0) +
ddr_bist_test_error;
ddr_bist_test_error =
dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0) +
ddr_bist_test_error;
}
printf("suspend dmc full test result = %d\n", ddr_bist_test_error);
#endif
printf("aml log : DDR suspend...test2\n");
apd_value = rd_reg(DMC_DRAM_APD_CTRL);
udelay(1);
wr_reg(DMC_DRAM_APD_CTRL, 0);
udelay(1);
//ddr_suspend_resume_test((1024<<20), 5000, 100, 100, 0, 0);
//return;
//st_f = st_f;
//unsigned int time_start, time_end;
printf("Enter ddr suspend test_loops = %d\n", test_loops);
//if (test_loops == 0) {
// dmc_ddr_test(0x10000000, 1, 0, 0, 0x30000000, 1, 0);
//test_loops++;
//}
test_loops++;
//some address will be protect by bl30
//return ;
while (0xfffffff != rd_reg(DMC_CHAN_STS)) {
printf("DMC_CHAN_STS: 0x%x\n", rd_reg(DMC_CHAN_STS));
#if BL30_SUSPEND_DEBUG_EN
/* ddr suspend debug : print vio reg and clear */
dmc_status_print_clear();
#endif
//vTaskDelay(pdMS_TO_TICKS(100000));
udelay(1);
}
#if BL30_SUSPEND_DEBUG_EN
/* ddr suspend debug : print vio before REQ_CTRL disabled*/
dmc_status_disable_print();
#endif
//time_start = rd_reg(P_ISA_TIMERE);
/* open DMC reg access for M3 */
//apb_sec_ctrl = rd_reg(DDR_APB_SEC_CTRL);
//wr_reg(DDR_APB_SEC_CTRL,0x91911);
printf("DMC_DRAM_MCFG: 0x%x\n", rd_reg(DMC_DRAM_MCFG));
udelay(1);
wr_reg(DMC_REQ_CTRL, 0); //bit0: A53.
udelay(1);
//return;
/* suspend flow */
//while ((((rd_reg(DMC_DRAM_STAT))&0xf0) != 0) && ((rd_reg(DMC_DRAM_STAT))&0xf0) != 0x40) {
// printf("DMC_DRAM_STAT11: 0x%x\n", rd_reg(DMC_DRAM_STAT));
// //vTaskDelay(pdMS_TO_TICKS(1));
// udelay(1);
//}
#ifdef DDR_SUSPEND_MODE_DMC_TRIGGER_SUSPEND_1
//bit 18 will auto trigger dfi init start cmd when scfg set to value 2
wr_reg(DMC_DRAM_ASR_CTRL, (1 << 18));
udelay(1);
wr_reg(DMC_DRAM_SCFG, 2);
udelay(1);
while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 3)) {
//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
}
#endif
#ifdef ENABLE_SET_MR2_REFRESH_RATE
char rank_index = 2;
char mrs_index = 2;
char ddr_type = get_dram_type();
unsigned int ddr4_mr2_value = update_and_get_ddr4_mr2_refresh_value();
printf("aml log : ddr_type = %x\n", ddr_type);
printf("aml log : ddr4_mr2_value = %x\n", ddr4_mr2_value);
ddr4_mr2_value = ((ddr4_mr2_value & 0x3fff) & ~(3 << 6)) |
(DDR4_MR2_FRESH_AUTO_MODE << 6);
#endif
#ifdef DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START
#ifdef ENABLE_SET_MR2_REFRESH_RATE
wr_reg(DMC_DRAM_SCFG, 1);
while (((((rd_reg(DMC_DRAM_STAT)) >> 4) & 0xf) != 1))
;
if (ddr_type == CONFIG_DDR_TYPE_DDR4)
set_dram_mrs(rank_index, mrs_index, ddr4_mr2_value, ddr_type);
#endif
wr_reg(DMC_DRAM_SCFG, 2);
udelay(2);
while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 3)) {
//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
//_udelay(2);//do not add any delay,since use ao cpu maybe speed too slow
}
udelay(2);
wr_reg(DMC_DRAM_SCFG, 1);
udelay(2);
//wr_reg(DMC_DRAM_MCFG, (1 << 9) | rd_reg(DMC_DRAM_MCFG));
while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 1)) {
//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
}
wr_reg(DMC_DRAM_DFIINITCFG, (1 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
//vTaskDelay(pdMS_TO_TICKS(1));
udelay(1);
wait_clr(DMC_DRAM_DFIINITCFG, 31);
#endif//final version, wait_clr
//vTaskDelay(pdMS_TO_TICKS(3));
udelay(3);
//return;
wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
udelay(1);
/* print time consumption */
//time_end = rd_reg(P_ISA_TIMERE);
//printf("ddr suspend time: %dus\n", time_end - time_start);
printf("\nddr suspend is done\n");
//ddr_suspend_resume_test((1024<<20), 100, 3, 3, 0, 0);
//ddr_suspend_resume_test((80<<20), 10000000, 0, 3, 0, 0);
}
//#if 1
static unsigned int pll_lock(void)
{
unsigned int lock_cnt = 1000;
//wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
//vTaskDelay(pdMS_TO_TICKS(1));
//udelay(100);
//wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0x1 << 29))) | (1 << 28));
do {
//vTaskDelay(pdMS_TO_TICKS(1));
udelay(1);
wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0xf << 28))) | (1 << 29));
//vTaskDelay(pdMS_TO_TICKS(1));
udelay(1);
wr_reg(AM_DDR_PLL_CNTL0, (rd_reg(AM_DDR_PLL_CNTL0) & (~(0x1 << 29))) | (1 << 28));
udelay(200);
} while ((0 == ((rd_reg(AM_DDR_PLL_CNTL0) >> 31) & 0x1)) && (lock_cnt--));
udelay(1000);
return lock_cnt;
}
//#endif
void vDDR_resume(uint32_t st_f)
{
//unsigned int time_start, time_end;
if (st_f)
return;
//st_f = st_f;
mdelay(30);
printf("Enter ddr resume\n");
uint32_t last_time = timere_read();
unsigned int cost_time = 0;
udelay(100);
cost_time = timere_read() - last_time;
printf("ddr test delay 100us = %d us\n", cost_time);
//return;
//time_start = rd_reg(P_ISA_TIMERE);
/* resume flow */
//#if 1
unsigned int ret = 0;
//unsigned int cost_time = 0;
last_time = timere_read();
ret = pll_lock();
if (!ret) {
printf("ddr pll lock r1\n");
wr_reg(AM_DDR_PLL_CNTL3, rd_reg(AM_DDR_PLL_CNTL3)|(1<<31));
udelay(1);
ret = pll_lock();
if (!ret) {
printf("ddr pll lock r2\n");
wr_reg(AM_DDR_PLL_CNTL6, 0x55540000);
udelay(1);
ret = pll_lock();
if (!ret) {
printf("ddr pll lock r2\n");
do {
} while (1);
}
}
}
cost_time = timere_read() - last_time;
printf("ddr resume pll done %d us\n", cost_time);
//#endif
//#if 1
#ifdef DDR_SUSPEND_MODE_DMC_TRIGGER_SUSPEND_1
#endif
#ifdef DDR_SUSPEND_MODE_MANUAL_TRIGGER_DFI_INIT_START
wr_reg(DMC_DRAM_DFIINITCFG, (0 | (0 << 1) | (0 << 6) | (0 << 14) | (1 << 8)));
//vTaskDelay(pdMS_TO_TICKS(1));
//printf("aml log : DDR suspend...dfi\n");
udelay(1);
wait_set(DMC_DRAM_DFIINITCFG, 31);
//vTaskDelay(pdMS_TO_TICKS(1));
udelay(1);
#endif
#ifdef ENABLE_SET_MR2_REFRESH_RATE
char rank_index = 2;
char mrs_index = 2;
char ddr_type = get_dram_type();
if (ddr_type == CONFIG_DDR_TYPE_DDR4)
set_dram_mrs(rank_index, mrs_index, global_ddr4_mr2_value, ddr_type);
#endif
wr_reg(DMC_DRAM_SCFG, 4);
udelay(1);
while (((((rd_reg(DMC_DRAM_STAT))>>4)&0xf) != 2)) {
//printf("DMC_DRAM_STAT22: 0x%x\n", readl(DMC_DRAM_STAT));
_udelay(1);//do not add any delay,since use ao cpu maybe speed too slow
}
//vTaskDelay(pdMS_TO_TICKS(1));
mdelay(10);//at least a refresh time to update zq dll
last_time = timere_read();
#if BL30_SUSPEND_DEBUG_EN
/* ddr suspend debug : print vio reg and channel status before resume */
show_dmc_port_status();
#endif
wr_reg(DMC_REQ_CTRL, 0xffffffff);
udelay(1);
//wr_reg(DDR_APB_SEC_CTRL, apb_sec_ctrl);
/* print time consumption */
//time_end = readl(P_ISA_TIMERE);
//printf("ddr resume time: %dus\n", time_end - time_start);
// unsigned int ddr_bist_test_error = 0;
//ddr_bist_test_error = dmc_ddr_test(dram_base, 0, 1, 1, test_size, 1, 0) + ddr_bist_test_error;
//ddr_bist_test_error = dmc_ddr_test(0, 0, 1, 1, (80<<20), 1, 0) + ddr_bist_test_error;
//printf("ddr_bist_test_error = %d\n", ddr_bist_test_error);
//wr_reg(0xfe002440, 2);
// wr_reg(0xfe002440, 0);
// _udelay(300);
//ddr_bist_test_error = dmc_ddr_test(0, 1, 0, 0, (1<<20), 1, 0) + ddr_bist_test_error;
//ddr_bist_test_error = dmc_ddr_test(0, 0, 1, 1, (1<<20), 1, 0) + ddr_bist_test_error;
// printf("ddr_bist_test_error = %d\n", ddr_bist_test_error);
//ddr_suspend_resume_test((1<<20), 2, 1, 3, 0, 0);
//ddr_suspend_resume_test((1<<20), 0, 1, 3, 0, 0);
//_udelay(300);
// wr_reg(DMC_REQ_CTRL, 0xffffffff);
cost_time = timere_read() - last_time;
printf("ddr resume done %d us\n", cost_time);
#ifdef ENABLE_DMC_DDR_TEST
unsigned int ddr_bist_test_error = 0;
//ddr_bist_test_error = dmc_ddr_test(TEST_START_ADDRESS, 1, 0, 0, TEST_END_ADDRESS, 1, 0);
ddr_bist_test_error = dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0);
if (ddr_bist_test_error) {
ddr_bist_test_error =
dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0) +
ddr_bist_test_error;
ddr_bist_test_error =
dmc_ddr_test(TEST_START_ADDRESS, 0, 1, 1, TEST_END_ADDRESS, 1, 0) +
ddr_bist_test_error;
}
printf("resume dmc full test result = %d\n", ddr_bist_test_error);
#endif
wr_reg(DMC_DRAM_APD_CTRL, apd_value);
wr_reg(DMC_DRAM_ASR_CTRL, (0 << 18));
}