/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #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)); }