cma扩充和开机logo消失问题分享
-
在使用的是128M dram的小内存配置,播放视频需要通过ion申请较多的连续物理内存空间,所以需要扩充CMA的大小,否则会导致cma扩充和开机logo消失。
【芯片平台】R311
【软件版本】tina3.5.1
【问题背景】
使用的是128MB的ddr,对于多视频播放和旋转的场景ion的使用非常吃紧,需要想办法扩大cma的大小。
【问题简述】
R311更改cma大小后,出现了不进kernel,开机logo消失等问题。
【问题处理过程】
(1)不进kernel:
更改cma大小为72MB后,系统无法进kernel,撤回修改,查看系统保留内存的分布:root@TinaLinux:/# cat /sys/kernel/debug/memblock/reserved 0: 0x40004000..0x40007fff, size:16K 1: 0x40020000..0x40020fff, size:4K 2: 0x40100000..0x40b480cb, size:10528K 3: 0x41000000..0x4100000b, size:0K 4: 0x43500000..0x4351617f, size:88K 5: 0x43c00000..0x47bfffff, size:65536K 6: 0x47cc8000..0x47f65fff, size:2680K 7: 0x47f7da00..0x47f961ff, size:98K 8: 0x47f9621c..0x47ffefff, size:419K 9: 0x47fff640..0x47fff67b, size:0K 10: 0x47fff680..0x47fff6bb, size:0K 11: 0x47fff6c0..0x47fff737, size:0K 12: 0x47fff740..0x47fff74f, size:0K 13: 0x47fff780..0x47fff78f, size:0K 14: 0x47fff7c0..0x47fff7c3, size:0K 15: 0x47fff800..0x47fff9ad, size:0K 16: 0x47fff9c0..0x47fffb6d, size:0K 17: 0x47fffb80..0x47fffd2d, size:0K 18: 0x47fffd40..0x47fffd43, size:0K 19: 0x47fffd64..0x47fffd81, size:0K 20: 0x47fffd84..0x47fffdb8, size:0K 21: 0x47fffdbc..0x47fffe1c, size:0K 22: 0x47fffe20..0x47fffe70, size:0K 23: 0x47fffe74..0x47ffff06, size:0K 24: 0x47ffff08..0x47ffff22, size:0K 25: 0x47ffff24..0x47ffff3e, size:0K 26: 0x47ffff40..0x47ffff5f, size:0K 27: 0x47ffff64..0x47ffff7e, size:0K 28: 0x47ffff80..0x47ffff8f, size:0K 29: 0x47ffff94..0x47ffffae, size:0K 30: 0x47ffffb0..0x47ffffff, size:0K
发现dts起始地址为0x43500000,cma的下一个保留区域起始地址为0x47cc8000,留给dts和cma的空间只有0x47cc8000-0x43500000约为71MB,cma大小设置为72MB后,超出了范围,导致不进kernel。怎么解决问题?把dts的起始地址往前挪动一下,cma的空间就可以得到扩充,如下所示,把dts的位置向前挪动0x00500000,cma足够容纳72MB的cma保留区域:
include/configs/sunxi-base.h: -#define CONFIG_SUNXI_FDT_ADDR SDRAM_OFFSET(0x03500000) +#define CONFIG_SUNXI_FDT_ADDR SDRAM_OFFSET(0x03000000)
修改后的保留内存的分布如下:
root@TinaLinux:/# cat /sys/kernel/debug/memblock/reserved 0: 0x40004000..0x40007fff, size:16K 1: 0x40020000..0x40020fff, size:4K 2: 0x40100000..0x40b480cb, size:10528K 3: 0x41000000..0x4100000b, size:0K 4: 0x43000000..0x4301617f, size:88K 5: 0x433fffff..0x47bfffff, size:73728K 6: 0x47cc8000..0x47f65fff, size:2680K 7: 0x47f7da00..0x47f961ff, size:98K 8: 0x47f9621c..0x47ffefff, size:419K 9: 0x47fff640..0x47fff67b, size:0K 10: 0x47fff680..0x47fff6bb, size:0K 11: 0x47fff6c0..0x47fff737, size:0K 12: 0x47fff740..0x47fff74f, size:0K 13: 0x47fff780..0x47fff78f, size:0K 14: 0x47fff7c0..0x47fff7c3, size:0K 15: 0x47fff800..0x47fff9ad, size:0K 16: 0x47fff9c0..0x47fffb6d, size:0K 17: 0x47fffb80..0x47fffd2d, size:0K 18: 0x47fffd40..0x47fffd43, size:0K 19: 0x47fffd64..0x47fffd81, size:0K 20: 0x47fffd84..0x47fffdb8, size:0K 21: 0x47fffdbc..0x47fffe1c, size:0K 22: 0x47fffe20..0x47fffe70, size:0K 23: 0x47fffe74..0x47ffff06, size:0K 24: 0x47ffff08..0x47ffff22, size:0K 25: 0x47ffff24..0x47ffff3e, size:0K 26: 0x47ffff40..0x47ffff5f, size:0K 27: 0x47ffff64..0x47ffff7e, size:0K 28: 0x47ffff80..0x47ffff8f, size:0K 29: 0x47ffff94..0x47ffffae, size:0K 30: 0x47ffffb0..0x47ffffff, size:0K
(2)开机logo消失:
开机logo是从uboot解码并显示的,找到logo解码的地方:compress_buf = get_decode_buffer(); if (compress_buf == NULL) { printf("bmp compress_buf empty,quit\n"); set_bmp_decode_flag(BMP_DECODE_FAIL); goto __third_cpu_end; } buf = (unsigned char *)(SUNXI_DISPLAY_FRAME_BUFFER_ADDR + SUNXI_DISPLAY_FRAME_BUFFER_SIZE); ret = sunxi_bmp_decode_from_compress(buf, compress_buf);
发现需要从地址compress_buf把logo的bmp格式数据解压到buf地址,buf地址为SUNXI_DISPLAY_FRAME_BUFFER_ADDR + SUNXI_DISPLAY_FRAME_BUFFER_SIZE,也就是0x47400000。compress_buf的地址如下所示:
if (next_mode == SUNXI_STATE_NORMAL_BOOT) { set_decode_buffer((unsigned char *) (SUNXI_LOGO_COMPRESSED_LOGO_BUFF)); } else if (next_mode == SUNXI_STATE_SHUTDOWN_CHARGE) {
从这里的代码片段知道,logo的原始数据放在地址SUNXI_LOGO_COMPRESSED_LOGO_BUFF,也就是0x43000010,而现在dts的区域的保留区域是( 0x43000000..0x4301617f),刚好覆盖到了SUNXI_LOGO_COMPRESSED_LOGO_BUFF。将SUNXI_LOGO_COMPRESSED_LOGO_BUFF改为0x42000000,这样就能使logo数据不落在内存的保留区域内。 然而编译后再验证,发现logo还是没法显示,从目前得到的信息看不到问题点,说明问题的原因还是没有全部被找到,继续跟进解码数据的过程:
int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize, unsigned char *inStream, SizeT length) { ....... /* Read the uncompressed size */ for (i = 0; i < 8; i++) { unsigned char b = inStream[LZMA_SIZE_OFFSET + i]; if (i < 4) { outSize += (UInt32)(b) << (i * 8); } else { outSizeHigh += (UInt32)(b) << ((i - 4) * 8); } } outSizeFull = (SizeT)outSize; if (sizeof(SizeT) >= 8) { /* * SizeT is a 64 bit uint => We can manage files larger than 4GB! * */ outSizeFull |= (((SizeT)outSizeHigh << 16) << 16); } else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) { /* * SizeT is a 32 bit uint => We cannot manage files larger than * 4GB! Assume however that all 0xf values is "unknown size" and * not actually a file of 2^64 bits. * */ if (outSizeHigh != (SizeT)-1 || outSize != (SizeT)-1) { debug ("LZMA: 64bit support not enabled.\n"); return SZ_ERROR_DATA; } } ....... }
如上面代码片段所示,检查*inStream(内存中的bmp数据)前面8位信息的时候,函数报错返回了,这里说明了内存中的bmp数据有问题。bmp数据需要先从flash里面拷贝到内存SUNXI_LOGO_COMPRESSED_LOGO_BUFF中,后面才能从SUNXI_LOGO_COMPRESSED_LOGO_BUFF解码出来 。现数据有异常,需要检查bmp数据从flash拷贝到内存的过程。查找SUNXI_LOGO_COMPRESSED_LOGO_BUFF使用的地方,arch/arm/cpu/armv7/sun8iw15p1/spl/fip_common.c里面有类似从flash拷贝logo数据到内存的代码:
arch/arm/cpu/armv7/sun8iw15p1/spl/fip_common.c: int load_fip(int *use_monitor) { ...... } else if (strncmp(toc1_item->name, ITEM_LOGO_NAME, sizeof(ITEM_LOGO_NAME)) == 0) { *(uint *)(SUNXI_LOGO_COMPRESSED_LOGO_SIZE_ADDR) = toc1_item->data_len; toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)SUNXI_LOGO_COMPRESSED_LOGO_BUFF); } else if (strncmp(toc1_item->name, ITEM_SHUTDOWNCHARGE_LOGO_NAME, sizeof(ITEM_SHUTDOWNCHARGE_LOGO_NAME)) == 0) { ...... }
从这段代码中看不出来有问题,再看看发现编译uboot的时候跟本不会编译到这个文件,怎么回事,询问负责uboot模块的同事得知,这里的文件是给boot0用的,logo数据从flash拷贝到内存的动作也是在boot0的时候做的。所以更新了SUNXI_LOGO_COMPRESSED_LOGO_BUFF的地址,还需要同时编译boot0,这样对于logo数据的拷贝和解码来说,SUNXI_LOGO_COMPRESSED_LOGO_BUFF才是相同的地址。
(文 by. shaokang)
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号