前言:
基于最新版 QDUTT(QCOM DDR USB TEST TOOL) 2.0.2 介绍了如何使用 QDUTT 对 QCM6490运行 DDR 调试映像 (DDI) 测试。本文对这些设备进行内存测试的软件工程师有用。
QCM6490中引入了 DDI,以提供 XML 绑定语言 (XBL) 的 DDR 测试环境,该平台DDI 测试嵌入到 xbl.elf 映像中,不再需要单独的 DDI 映像 (ddi.elf)。用户在进行 DDI 测试之前必须刷写整个编译映像(非 HLOS 映像和 HLOS 映像)。
内容:
所有 DDI 测试用例均存储在文件 ddi_protocol_config.xml 中,该 xml 文件与每个 BOOT CRM版本一起打包为二进制文件。该文件还会反映所有测试用例及其输入和预期输出。
QDUTT 属于 PC 工具,用于与 DDI 进行通信,以便在目标设备上运行 DDI 测试用例。QDUTT 会解析 ddi_protocol_config.xml,然后通过 QDUTT GUI 显示所有 DDI 支持的测试用例。QDUTT 通过调用 ddi.py python 脚本来运行 DDI 测试用例。
boot_images/boot/QcomPkg/Tools/DDI/ddi_protocol_config.xml
DDI python 脚本 ddi.py 将用户在 QDUTT GUI 中选择的 DDI 测试命令(识别为 DDI 测试标志)集成到 xbl_config 分区,一旦 XBL 检测到 DDI 测试标志,XBL 便会跳到 DDI 项运行DDI 测试,而不运行正常启动例程。
SDM845/SM6150/QCM6490/SM8250/SM7250 DDI 测试用
例(不同平台测试用例数量可能不一样):
读取
写入
读-写
延迟
频率切换
眼图
获取设备信息
读取接口设置(或读取 eCDT)
读取 AC 时序
获取安全模式信息
boot_images/boot/QcomPkg/Tools/DDI/ddi.py
测试步骤:
1、 从QPM安装QDUTT。 2、 打开QDUTT,选择DDI。3、 选择standard mode。
4、 选择standard mode,选择qcm6490-la-1-0_amss_standard_oem\boot_images\boot\QcomPkg\Tools\DDI\ddi_protocol_config.xml
注意此文件一定要从编译环境中取,你测试的版本编译环境要保留,下面选择的文件都是从里面取的
4、选择如下几个文件,partition.xml这个可能没有此文件,如你当前使用的是partition_ext.xml,拷贝重命名为partition.xml
cm6490-la-1-0_amss_standard_oem\common\config\ufs\partition.xml
qcm6490-la-1-0_amss_standard_oem\common\build\ufs\rawprogram1.xml
qcm6490-la-1-0_amss_standard_oem\common\build\ufs\rawprogram3.xml
5、设备开机,执行adb reboot edl,进9008模式下开始测试。一般我们测试先测试眼图,参数使用默认的参数,按步骤执行。
6、测试成功会生成一个表格,数据就可以绘制眼图的。从log也可以看到测试成功了:
DEBUG:
1.关于读写测试的参数:
Start Addr (uint64) – 起始地址(物理地址映射)。如果值为 0,则会自动将地址设为 DDR
内存区的开始处。
[默认值:0]
End Addr (uint64) – 结束地址(物理地址映射)。如果值为 0,则会自动将地址设为 DDR
内存区的结尾处。
[默认值:0]
Repeat Count (uint64) – 读取操作的重复次数。如果值为 0,则将不断重复。
[默认值:1]
Write Flags (uint8) – 代表不同测试选项的位域。可设置下列位的任意组合。
[默认值:1]
Random Seed (uint32) – 生成随机数据需要使用的种子值。如果为 0,则将动态生成种子。
[默认值:0]
Random Stride (uint64) – 要生成的随机数据的 64 位字数量。随后将重复复制该数据,以
填充已定义测试内存区之间的整个空间。
[默认值:0]
Pattern – PC安装路径下有此xml,C:\Program Files (x86)\Qualcomm\QDUTT\data_pattern.xml
2.测试read或者read-write过程发现死机,使用默认参数或者设置为0x80000000 ~ 0x500000000(正常测试过程直接使用默认参数即可,工具及代码会自动获取DDR起始和结束地址的)。
此时改小 0x8000 0000- 0x9000 0000,单测read可以测过,注意工具里的值是十进制的,代码打印是16进制
死机log
D - 51057 - do_ddr_training, Delta
D - 58896 - sbl1_do_ddr_training
B - 904904 - DDI: Memory Test command
B - 908290 - initial test range: 0x80000000 ~ 0x500000000
B - 912011 - test range: 0x80000000 ~ 0x500000000
B - 917562 - random_stride: 0 random_seed: 0xb33e0870
B - 922564 - repeat: 1 verify: 1 invert,0
B - 928237 - Start Write test #1
B - 57656346 - Error code 9 at boot_error_handler.c Line 724
B - 57656376 - Call Stack:
B - 57661988 - func_addr : 1482007C
B - 57664581 - func_addr : 1481D3D8
B - 57668271 - ^^^^^^^^^^^^^^^^^^^^^
B - 57671931 - sbl_error_handler FAIL: DDR not initialized
B - 57675439 - sbl_crashdump_reset_with_dload: Ramdump not allowed. Go▒Format: Log Type - Time(microsec) - Message - Optional Info
Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
S - QC_IMAGE_VERSION_STRING=BOOT.MXF.1.0-00806-LAHAINA-1
产生该死机的原因是QCM6490平台只支持到2通道,所以测试代码这里有问题:
uint64* ddi_get_cs0_end()
{uint32 i;void* ret = (void*)ddr_shared_data->ddr_size_info.ddr_cs0_remapped_addr[0];for (i = 0; i < ddr_shared_data->num_channel; i++){ret += ddr_shared_data->ddr_size_info.ddr_cs0_mb[i] << 20;}return (uint64*)ret;
}uint64* ddi_get_cs1_end()
{uint32 i;void* ret = (void*)ddr_shared_data->ddr_size_info.ddr_cs1_remapped_addr[0];
//这里4改成2,四通道改成双通道;或者改成ddr_shared_data->num_channel也是可以的,修改后读写测试passfor (i = 0; i < 2; i++) {ret += ddr_shared_data->ddr_size_info.ddr_cs1_mb[0] << 20;}if (ret == 0) {return ddi_get_cs0_end();} else {return (uint64*)ret;}
}
通过打印:
f boot_images\boot\QcomPkg\SocPkg\Kodiak\Library\DDRTargetLib/ddr_target.c
void ddr_regions_remapper(void)
{
char ddr_log_string[50]; /*add*/
uint64 ddr_cs0_address=0, ddr_cs1_address=0;
...
...
/* Update HBB */
ddr_driver_struct->ddr_regions_info.highest_bank_bit = ddr_shared_data->device_params.highest_bank_bit;
/*add below logs at the end of function*/
snprintf(ddi_log_string, sizeof(ddi_log_string), "ddr_size: 0x%lx,0x%lx", ddr_cs0_size,ddr_cs1_size);
boot_log_message(ddi_log_string);snprintf(ddi_log_string, sizeof(ddi_log_string), "remapped_addr: 0x%lx,0x%lx", ddr_shared_data->ddr_size_info.ddr_cs0_remapped_addr[0],ddr_shared_data->ddr_size_info.ddr_cs1_remapped_addr[0]);
boot_log_message(ddi_log_string);
} /* ddr_regions_remapper */
boot_images\boot\QcomPkg\SocPkg\Kodiak\Library\DDITargetLib\ddi_test_cases.c
ddi_run_command_rdwr ()
{
....
/*add below log before calling get_start_end */
#if DDI_PRINT_ENABLE
snprintf(ddi_log_string, sizeof(ddi_log_string), "initial test range: 0x%lx ~ 0x%lx", start, end);
boot_log_message(ddi_log_string);
#endif
// Set minimum repeat count as 1
if(repeat_count < 1)
repeat_count =1;ret |= get_start_end((uint64*)&start, (uint64*)&end);#if DDI_PRINT_ENABLE
snprintf(ddi_log_string, sizeof(ddi_log_string), " test range: 0x%lx ~ 0x%lx", start, end);
boot_log
...
}
3.未修改代码前,如下是设置地址为0x80000000 ~ 0x380000000的log-OVERFLOW;设置0x80000000 ~ 0x370000000可以测试通过:
如果地址格式对的,但是超出DDR实际地址范围?
如果地址格式(比如8位的数据,你填写的数据不满足8位)不对,会打印?
实际还是和通道数量相关,修改通道后0x380000000可以测试通过。
S - Core 0 Frequency, 1516 MHz
S - PBL Patch Ver: 0
D - 6626 - pbl_apps_init_timestamp
D - 327043 - bootable_media_detect_timestamp
D - 193523647 - bl_elf_metadata_loading_timestamp
D - 703 - bl_hash_seg_auth_timestamp
D - 279518 - bl_elf_loadable_segment_loading_timestamp
D - 5495 - bl_elf_segs_hash_verify_timestamp
D - 17248 - bl_sec_hash_seg_auth_timestamp
D - 821 - bl_sec_segs_hash_verify_timestamp
D - 29 - pbl_populate_shared_data_and_exit_timestamp
S - 194161130 - PBL, End
B - OVERFLOW - SBL1, Start
B - OVERFLOW - SBL1 BUILD @ 16:06:08 on Oct 21 2021
D - OVERFLOW - sbl1_hw_init
B - OVERFLOW - Entering DeviceProg lite
B - OVERFLOW - usb: init start
B - OVERFLOW - usb: qusb_dci_platform
B - OVERFLOW - usb: enum_carried_from_pbl
B - OVERFLOW - usb: HIGH , 0x900e
B - OVERFLOW - usb: timer_start , 0x4c4b40
B - OVERFLOW - usb: ENUM success
B - OVERFLOW - usb: VBUS High!
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - UFS INQUIRY ID: SAMSUNG KMJS9001RM-BG01 0200
B - OVERFLOW - UFS Boot LUN: 1
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - usb: host sends ZLP
B - OVERFLOW - usb: bulk_shutdown
B - OVERFLOW - usb: endxfer EP0 OUT
Format: Log Type - Time(microsec) - Message - Optional Info
Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
S - QC_IMAGE_VERSION_STRING=BOOT.MXF.1.0-00806-LAHAINA-1
4.从如下log可以看出读写测试成功:
工具:
Run command successfullynew ddr partition flashed to device
串口log:
B - 825787 - Manufacturer ID = 1, Device Type = 8
B - 829386 - Rank 0 size = 6144 MB, Rank 1 size = 6144 MB
D - 30683 - sbl1_ddr_init
D - 152 - boot_pre_ddi_entry
B - 842501 - do_ddr_training, Start
B - 883676 - DDR: Start of DDR Training Restore
B - 887367 - Current DDR Freq = 2096 MHz
B - 888343 - Max enabled DDR Freq = 2736 MHz
B - 892369 - DDR: End of DDR Training Restore
D - 51057 - do_ddr_training, Delta
D - 58896 - sbl1_do_ddr_training
B - 904813 - DDI: memory read command
B - 908198 - test range: 0x80000000 ~ 0x380000000
B - 911950 - repeat_count: 1
B - 917196 - Start Read Test #1
B - 262748655 - ** PASS **
B - 262748685 - DDI: ddr write command
B - 262751217 - test range: 0x80000000 ~ 0x380000000
B - 262754755 - repeat_count: 1
B - 262759757 - random_stride: 0, random_seed: 0xb33e0870
B - 262762898 - invert_row: 0
B - 262768541 - Start Write Test #1
B - 319511198 - ** PASS **
B - 3195Format: Log Type - Time(microsec) - Message - Optional Info
Log Type: B - Since Boot(Power On Reset), D - Delta, S - Statistic
附:如果DDR training后设置了最大频率导致无法开机,可以尝试通过QDUTT关闭最大频率看能否开机 80-nr058-6:
eDCT --> Open existing eCDT JSON file --> Override Type -->Disable Frequencies
实际上,我们当前json文件由于权限问题不能选择7325,所以这个可以先不用管
如此会重新编译生成xbl_config.elf下载进去即关闭最大频率